Skip to content

Commit 6764a65

Browse files
committed
Move update.go logic to a command line program
This will make it easier to break out functionality in the update script and then test it using go test. This also modifies the command line program to allow variants to override the existing values from the base image.
1 parent bccbf96 commit 6764a65

File tree

14 files changed

+606
-408
lines changed

14 files changed

+606
-408
lines changed

Jenkinsfile

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pipeline {
5151
}
5252
}
5353

54-
stage('Update official images') {
54+
stage('Checkout official images') {
5555
steps {
5656
dir('official-images') {
5757
checkout(
@@ -69,11 +69,19 @@ pipeline {
6969
// Reset master to the value at origin.
7070
sh "git checkout master && git reset --hard origin/master"
7171
}
72+
}
73+
}
7274

73-
withDockerContainer(image: "golang:1.9.1-stretch") {
74-
sh 'cd influxdata-docker; go run update.go -n'
75+
stage('Update official images') {
76+
agent {
77+
dockerfile {
78+
dir 'dockerlib'
7579
}
7680
}
81+
82+
steps {
83+
sh "dockerlib update"
84+
}
7785
}
7886

7987
stage('Push changes to GitHub') {

chronograf/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
"arm64v8"
88
],
99
"variants": [
10-
"alpine"
10+
{"name": "alpine"}
1111
]
1212
}

circle-test.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ tags=()
3232

3333
# Gather directories with a Dockerfile and sanitize the path to remove leading
3434
# a leading ./ and multiple slashes into a single slash.
35-
dockerfiles=$(find "$dir" -name nightly -prune -o -name Dockerfile -print0 | xargs -0 -I{} dirname {} | sed 's@^./@@' | sed 's@//*@/@g')
35+
dockerfiles=$(find "$dir" -name nightly -prune -o -name Dockerfile -print0 | grep -v dockerlib | xargs -0 -I{} dirname {} | sed 's@^./@@' | sed 's@//*@/@g')
3636
for path in $dockerfiles; do
3737
# Generate a tag by replacing the first slash with a colon and all remaining slashes with a dash.
3838
tag=$(echo $path | sed 's@/@:@' | sed 's@/@-@g')

dockerlib/Dockerfile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
FROM golang:1.9.2-stretch as builder
2+
COPY . /go/src/github.com/influxdata/influxdata-docker/dockerlib
3+
RUN set -xe && \
4+
go get -d github.com/influxdata/influxdata-docker/dockerlib && \
5+
go install github.com/influxdata/influxdata-docker/dockerlib
6+
7+
FROM debian:stretch
8+
COPY --from=builder /go/bin/dockerlib /usr/bin/dockerlib
9+
ENTRYPOINT ["/usr/bin/dockerlib"]

dockerlib/commands.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package main
2+
3+
import (
4+
"os"
5+
6+
"path/filepath"
7+
8+
"fmt"
9+
10+
"github.com/influxdata/influxdata-docker/dockerlib/dockerlib"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
var RootCmd = &cobra.Command{
15+
Use: "dockerlib",
16+
Short: "Manage docker official images",
17+
}
18+
19+
var UpdateCmd = &cobra.Command{
20+
Use: "update",
21+
Short: "Update the official-images repository",
22+
Run: func(cmd *cobra.Command, args []string) {
23+
if err := Update(); err != nil {
24+
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
25+
os.Exit(1)
26+
}
27+
},
28+
}
29+
30+
func Update() error {
31+
// Locate all of the manifests within this repository.
32+
manifests, err := dockerlib.FindImageManifests()
33+
if err != nil {
34+
return err
35+
}
36+
37+
for _, m := range manifests {
38+
header := dockerlib.Header{}
39+
header.Add("Maintainers", getDefaultMaintainer())
40+
header.Add("GitRepo", remoteRepo)
41+
42+
rev, err := latestRev(m.BaseDir)
43+
if err != nil {
44+
return err
45+
}
46+
header.Add("GitCommit", rev)
47+
48+
if err := func() error {
49+
f, err := os.Create(filepath.Join("../official-images/library", m.Name))
50+
if err != nil {
51+
return err
52+
}
53+
defer f.Close()
54+
55+
if err := m.Write(f, &header); err != nil {
56+
return err
57+
}
58+
return f.Close()
59+
}(); err != nil {
60+
return err
61+
}
62+
}
63+
return nil
64+
}
65+
66+
func init() {
67+
RootCmd.AddCommand(UpdateCmd)
68+
}

dockerlib/dockerlib/header.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package dockerlib
2+
3+
import (
4+
"container/list"
5+
"fmt"
6+
"io"
7+
"strings"
8+
)
9+
10+
type keyValuePair struct {
11+
key string
12+
values []string
13+
}
14+
15+
type Header struct {
16+
values *list.List
17+
index map[string]*list.Element
18+
}
19+
20+
func (h *Header) Add(key, value string) {
21+
e, ok := h.index[key]
22+
if !ok {
23+
h.Set(key, value)
24+
return
25+
}
26+
27+
kv := e.Value.(*keyValuePair)
28+
kv.values = append(kv.values, value)
29+
}
30+
31+
func (h *Header) Set(key, value string) {
32+
if h.index == nil {
33+
h.index = make(map[string]*list.Element)
34+
}
35+
if h.values == nil {
36+
h.values = list.New()
37+
}
38+
values := make([]string, 1)
39+
values[0] = value
40+
h.index[key] = h.values.PushBack(&keyValuePair{
41+
key: key,
42+
values: values,
43+
})
44+
}
45+
46+
func (h *Header) Write(w io.Writer) error {
47+
for front := h.values.Front(); front != nil; front = front.Next() {
48+
kv := front.Value.(*keyValuePair)
49+
if _, err := fmt.Fprintf(w, "%s: %s\n", kv.key, strings.Join(kv.values, ", ")); err != nil {
50+
return err
51+
}
52+
}
53+
return nil
54+
}

dockerlib/dockerlib/manifest.go

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package dockerlib
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
"io/ioutil"
8+
"os"
9+
"path/filepath"
10+
"strconv"
11+
"strings"
12+
)
13+
14+
type ImageManifest struct {
15+
Name string `json:"name"`
16+
BaseDir string `json:"-"`
17+
Versions []*Version `json:"versions"`
18+
Architectures []string `json:"architectures"`
19+
Variants []*Variant `json:"variants"`
20+
Latest string `json:"-"`
21+
}
22+
23+
type Variant struct {
24+
Name string `json:"name"`
25+
Versions []*Version `json:"versions"`
26+
Architectures []string `json:"architectures"`
27+
Latest string `json:"-"`
28+
}
29+
30+
func FindImageManifests() ([]*ImageManifest, error) {
31+
var manifests []*ImageManifest
32+
if err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
33+
if err != nil {
34+
return err
35+
} else if info.IsDir() && info.Name() == ".git" {
36+
return filepath.SkipDir
37+
}
38+
39+
// Check if there is a manifest.json in this folder.
40+
if info.Name() != "manifest.json" {
41+
return nil
42+
}
43+
44+
// We found a manifest.json in this folder. Read and parse it into a manifest.
45+
manifest, err := ReadImageManifest(path)
46+
if err != nil {
47+
return err
48+
}
49+
manifests = append(manifests, manifest)
50+
return nil
51+
}); err != nil {
52+
return nil, err
53+
}
54+
return manifests, nil
55+
}
56+
57+
func ReadImageManifest(fpath string) (*ImageManifest, error) {
58+
in, err := ioutil.ReadFile(fpath)
59+
if err != nil {
60+
return nil, err
61+
}
62+
63+
var manifest ImageManifest
64+
if err := json.Unmarshal(in, &manifest); err != nil {
65+
return nil, err
66+
}
67+
manifest.BaseDir = filepath.Dir(fpath)
68+
69+
// Look through each of the versions to determine which is the latest.
70+
if len(manifest.Versions) > 0 {
71+
manifest.Latest = Versions(manifest.Versions).Latest().String()
72+
}
73+
74+
// Propagate the image values to the variants and determine the base directory
75+
// and the latest version.
76+
for _, variant := range manifest.Variants {
77+
if len(variant.Versions) == 0 {
78+
variant.Versions = manifest.Versions
79+
variant.Latest = manifest.Latest
80+
} else {
81+
variant.Latest = Versions(variant.Versions).Latest().String()
82+
}
83+
}
84+
return &manifest, nil
85+
}
86+
87+
func (m *ImageManifest) Write(w io.Writer, header *Header) error {
88+
// Output the initial header passed in to write.
89+
if header != nil {
90+
header.Write(w)
91+
}
92+
93+
// Determine all of the versions.
94+
for _, v := range m.Versions {
95+
dir := filepath.Join(m.BaseDir, v.String())
96+
97+
header := &Header{}
98+
version, err := DockerfileVersion(dir)
99+
if err != nil {
100+
return err
101+
}
102+
for i := 2; i <= len(version.Segments()); i++ {
103+
segments := version.Segments()
104+
parts := make([]string, i)
105+
for j, s := range segments[:i] {
106+
parts[j] = strconv.Itoa(s)
107+
}
108+
header.Add("Tags", strings.Join(parts, "."))
109+
}
110+
if m.Latest == v.String() {
111+
header.Add("Tags", "latest")
112+
}
113+
for _, arch := range m.Architectures {
114+
header.Add("Architectures", arch)
115+
}
116+
header.Add("Directory", dir)
117+
118+
fmt.Fprintln(w)
119+
if err := header.Write(w); err != nil {
120+
return err
121+
}
122+
123+
for _, variant := range m.Variants {
124+
// Check if this variant is included in the list of versions.
125+
found := false
126+
for _, vv := range variant.Versions {
127+
if v.String() == vv.String() {
128+
found = true
129+
break
130+
}
131+
}
132+
133+
// Skip this variant if the version isn't found in the variant.
134+
if !found {
135+
continue
136+
}
137+
138+
header := &Header{}
139+
version, err := DockerfileVersion(dir)
140+
if err != nil {
141+
return err
142+
}
143+
for i := 2; i <= len(version.Segments()); i++ {
144+
segments := version.Segments()
145+
parts := make([]string, i)
146+
for j, s := range segments[:i] {
147+
parts[j] = strconv.Itoa(s)
148+
}
149+
header.Add("Tags", strings.Join(parts, ".")+"-"+variant.Name)
150+
}
151+
if m.Latest == v.String() {
152+
header.Add("Tags", variant.Name)
153+
}
154+
for _, arch := range variant.Architectures {
155+
header.Add("Architectures", arch)
156+
}
157+
header.Add("Directory", filepath.Join(dir, variant.Name))
158+
//header.Add("Tags", variant.Name)
159+
fmt.Fprintln(w)
160+
if err := header.Write(w); err != nil {
161+
return err
162+
}
163+
}
164+
}
165+
166+
return nil
167+
}

0 commit comments

Comments
 (0)