Merge pull request #331 from burdiyan/master

Implement support for digests in imageTags
This commit is contained in:
Jeff Regan
2018-09-10 10:57:53 -07:00
committed by GitHub
6 changed files with 63 additions and 21 deletions

View File

@@ -247,8 +247,12 @@ vars:
# image: nginx:1.7.9
#```
# one can change the tag of myimage to v1 and the tag of nginx to 1.8.0 with the following:
#
# It also supports digests. If digest is present newTag is ignored.
imageTags:
- name: mycontainerregistry/myimage
newTag: v1
- name: nginx
newTag: 1.8.0
- name: alpine
digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3

View File

@@ -20,6 +20,7 @@ import (
"errors"
"regexp"
"sort"
"strings"
"github.com/spf13/cobra"
@@ -29,7 +30,7 @@ import (
)
type setImageTagOptions struct {
imageTagMap map[string]string
imageTagMap map[string]types.ImageTag
}
var pattern = regexp.MustCompile("^(.*):([a-zA-Z0-9._-]*)$")
@@ -40,10 +41,10 @@ func newCmdSetImageTag(fsys fs.FileSystem) *cobra.Command {
cmd := &cobra.Command{
Use: "imagetag",
Short: "Sets images and their new tags in the kustomization file",
Short: "Sets images and their new tags or digests in the kustomization file",
Example: `
The command
set imagetag nginx:1.8.0 my-app:latest
set imagetag nginx:1.8.0 my-app:latest alpine@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
will add
imageTags:
@@ -51,9 +52,11 @@ imageTags:
newTag: 1.8.0
- name: my-app
newTag: latest
- name: alpine
digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
to the kustomization file if it doesn't exist,
and overwrite the previous newTag if the image name exists.
and overwrite the previous ones if the image tag exists.
`,
RunE: func(cmd *cobra.Command, args []string) error {
err := o.Validate(args)
@@ -69,15 +72,28 @@ and overwrite the previous newTag if the image name exists.
// Validate validates setImageTag command.
func (o *setImageTagOptions) Validate(args []string) error {
if len(args) == 0 {
return errors.New("no image and newTag specified")
return errors.New("no image specified")
}
o.imageTagMap = make(map[string]string)
o.imageTagMap = make(map[string]types.ImageTag)
for _, arg := range args {
imagetag := pattern.FindStringSubmatch(arg)
if len(imagetag) != 3 {
return errors.New("invalid format of imagetag, must specify it as <image>:<newtag>")
if s := strings.Split(arg, "@"); len(s) > 1 {
o.imageTagMap[s[0]] = types.ImageTag{
Name: s[0],
Digest: s[1],
}
continue
}
s := pattern.FindStringSubmatch(arg)
if len(s) != 3 {
return errors.New("invalid format of imagetag, must specify it as <image>:<newtag> or <image>@<digest>")
}
o.imageTagMap[s[1]] = types.ImageTag{
Name: s[1],
NewTag: s[2],
}
o.imageTagMap[imagetag[1]] = imagetag[2]
}
return nil
}
@@ -92,16 +108,18 @@ func (o *setImageTagOptions) RunSetImageTags(fsys fs.FileSystem) error {
if err != nil {
return err
}
imageTagMap := map[string]string{}
for _, it := range m.ImageTags {
imageTagMap[it.Name] = it.NewTag
}
for key, value := range o.imageTagMap {
imageTagMap[key] = value
if _, ok := o.imageTagMap[it.Name]; ok {
continue
}
o.imageTagMap[it.Name] = it
}
var imageTags []types.ImageTag
for key, value := range imageTagMap {
imageTags = append(imageTags, types.ImageTag{Name: key, NewTag: value})
for _, v := range o.imageTagMap {
imageTags = append(imageTags, v)
}
sort.Slice(imageTags, func(i, j int) bool {
return imageTags[i].Name < imageTags[j].Name

View File

@@ -29,7 +29,8 @@ func TestSetImageTagsHappyPath(t *testing.T) {
fakeFS.WriteFile(constants.KustomizationFileName, []byte(kustomizationContent))
cmd := newCmdSetImageTag(fakeFS)
args := []string{"image1:tag1", "image2:tag2", "localhost:5000/operator:1.0.0"}
args := []string{"image1:tag1", "image2:tag2", "localhost:5000/operator:1.0.0",
"foo.bar.baz:5000/one/two@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3"}
err := cmd.RunE(cmd, args)
if err != nil {
t.Errorf("unexpected cmd error: %v", err)
@@ -40,6 +41,8 @@ func TestSetImageTagsHappyPath(t *testing.T) {
}
expected := []byte(`
imageTags:
- digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
name: foo.bar.baz:5000/one/two
- name: image1
newTag: tag1
- name: image2
@@ -93,7 +96,7 @@ func TestSetImageTagsNoArgs(t *testing.T) {
if err == nil {
t.Errorf("expected error: %v", err)
}
if err.Error() != "no image and newTag specified" {
if err.Error() != "no image specified" {
t.Errorf("incorrect error: %v", err.Error())
}
}

View File

@@ -18,7 +18,6 @@ package transformers
import (
"regexp"
"strings"
"github.com/kubernetes-sigs/kustomize/pkg/resmap"
"github.com/kubernetes-sigs/kustomize/pkg/types"
@@ -83,7 +82,12 @@ func (pt *imageTagTransformer) updateContainers(obj map[string]interface{}, path
}
for _, imagetag := range pt.imageTags {
if isImageMatched(image.(string), imagetag.Name) {
container["image"] = strings.Join([]string{imagetag.Name, imagetag.NewTag}, ":")
container["image"] = imagetag.Name + ":" + imagetag.NewTag
if imagetag.Digest != "" {
container["image"] = imagetag.Name + "@" + imagetag.Digest
}
break
}
}

View File

@@ -50,6 +50,10 @@ func TestImageTagTransformer(t *testing.T) {
"name": "nginx",
"image": "nginx:1.7.9",
},
map[string]interface{}{
"name": "replaced-with-digest",
"image": "foobar:1",
},
},
},
},
@@ -114,6 +118,10 @@ func TestImageTagTransformer(t *testing.T) {
"name": "nginx",
"image": "nginx:v2",
},
map[string]interface{}{
"name": "replaced-with-digest",
"image": "foobar@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3",
},
},
},
},
@@ -160,6 +168,7 @@ func TestImageTagTransformer(t *testing.T) {
{Name: "nginx", NewTag: "v2"},
{Name: "my-nginx", NewTag: "previous"},
{Name: "myprivaterepohostname:1234/my/image", NewTag: "v1.0.1"},
{Name: "foobar", Digest: "sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3"},
})
if err != nil {
t.Fatalf("unexpected error: %v", err)

View File

@@ -176,4 +176,8 @@ type ImageTag struct {
// NewTag is the value to use in replacing the original tag.
NewTag string `json:"newTag,omitempty" yaml:"newTag,omitempty"`
// Digest is the value used to replace the original image tag.
// If digest is present NewTag value is ignored.
Digest string `json:"digest,omitempty" yaml:"digest,omitempty"`
}