diff --git a/kustomize/internal/commands/edit/set/setimage.go b/kustomize/internal/commands/edit/set/setimage.go index e8e813614..91e79b1c0 100644 --- a/kustomize/internal/commands/edit/set/setimage.go +++ b/kustomize/internal/commands/edit/set/setimage.go @@ -20,7 +20,9 @@ type setImageOptions struct { imageMap map[string]types.Image } -var pattern = regexp.MustCompile("^(.*):([a-zA-Z0-9._-]*)$") +var pattern = regexp.MustCompile(`^(.*):([a-zA-Z0-9._-]*|\*)$`) + +var preserveSeparator = "*" // errors @@ -74,7 +76,8 @@ images: to the kustomization file if it doesn't exist, and overwrite the previous ones if the image name exists. -The image tag can only contain alphanumeric, '.', '_' and '-'. +The image tag can only contain alphanumeric, '.', '_' and '-'. Passing * (asterisk) either as the new name, +the new tag, or the digest will preserve the appropriate values from the kustomization file. `, RunE: func(cmd *cobra.Command, args []string) error { err := o.Validate(args) @@ -125,7 +128,25 @@ func (o *setImageOptions) RunSetImage(fSys filesys.FileSystem) error { // append only new images from kustomize file for _, im := range m.Images { - if _, ok := o.imageMap[im.Name]; ok { + if argIm, ok := o.imageMap[im.Name]; ok { + + // Reuse the existing new name when asterisk new name is passed + if argIm.NewName == preserveSeparator { + argIm = replaceNewName(argIm, im.NewName) + } + + // Reuse the existing new tag when asterisk new tag is passed + if argIm.NewTag == preserveSeparator { + argIm = replaceNewTag(argIm, im.NewTag) + } + + // Reuse the existing digest when asterisk disgest is passed + if argIm.Digest == preserveSeparator { + argIm = replaceDigest(argIm, im.Digest) + } + + o.imageMap[im.Name] = argIm + continue } @@ -134,6 +155,19 @@ func (o *setImageOptions) RunSetImage(fSys filesys.FileSystem) error { var images []types.Image for _, v := range o.imageMap { + + if v.NewName == preserveSeparator { + v = replaceNewName(v, "") + } + + if v.NewTag == preserveSeparator { + v = replaceNewTag(v, "") + } + + if v.Digest == preserveSeparator { + v = replaceDigest(v, "") + } + images = append(images, v) } @@ -145,6 +179,33 @@ func (o *setImageOptions) RunSetImage(fSys filesys.FileSystem) error { return mf.Write(m) } +func replaceNewName(image types.Image, newName string) types.Image { + return types.Image{ + Name: image.Name, + NewName: newName, + NewTag: image.NewTag, + Digest: image.Digest, + } +} + +func replaceNewTag(image types.Image, newTag string) types.Image { + return types.Image{ + Name: image.Name, + NewName: image.NewName, + NewTag: newTag, + Digest: image.Digest, + } +} + +func replaceDigest(image types.Image, digest string) types.Image { + return types.Image{ + Name: image.Name, + NewName: image.NewName, + NewTag: image.NewTag, + Digest: digest, + } +} + func parse(arg string) (types.Image, error) { // matches if there is an image name to overwrite diff --git a/kustomize/internal/commands/edit/set/setimage_test.go b/kustomize/internal/commands/edit/set/setimage_test.go index c1f298d81..77a3b308c 100644 --- a/kustomize/internal/commands/edit/set/setimage_test.go +++ b/kustomize/internal/commands/edit/set/setimage_test.go @@ -251,6 +251,161 @@ func TestSetImage(t *testing.T) { err: errImageInvalidArgs, }, }, + { + description: "override new tag but keep new name", + given: given{ + args: []string{"image1=*:v1"}, + infileImages: []string{ + "images:", + "- name: image1", + " newName: foo.bar.foo:8800/foo/image1", + " newTag: my-tag", + }, + }, + expected: expected{ + fileOutput: []string{ + "images:", + "- name: image1", + " newName: foo.bar.foo:8800/foo/image1", + " newTag: v1", + }}, + }, + { + description: "override new name but keep new tag", + given: given{ + args: []string{"image1=my-image1:*"}, + infileImages: []string{ + "images:", + "- name: image1", + " newName: foo.bar.foo:8800/foo/image1", + " newTag: my-tag", + }, + }, + expected: expected{ + fileOutput: []string{ + "images:", + "- name: image1", + " newName: my-image1", + " newTag: my-tag", + }}, + }, + { + description: "keep new name and new tag (rare case)", + given: given{ + args: []string{"image1=*:*"}, + infileImages: []string{ + "images:", + "- name: image1", + " newName: my-image1", + " newTag: my-tag", + }, + }, + expected: expected{ + fileOutput: []string{ + "images:", + "- name: image1", + " newName: my-image1", + " newTag: my-tag", + }}, + }, + { + description: "do not set asterisk as new name for existing image", + given: given{ + args: []string{"image1=*:v1"}, + infileImages: []string{ + "images:", + "- name: image1", + " newTag: my-tag", + }, + }, + expected: expected{ + fileOutput: []string{ + "images:", + "- name: image1", + " newTag: v1", + }}, + }, + { + description: "do not set asterisk as new name", + given: given{ + args: []string{"image1=*:v1"}, + }, + expected: expected{ + fileOutput: []string{ + "images:", + "- name: image1", + " newTag: v1", + }}, + }, + { + description: "do not set asterisk as new tag", + given: given{ + args: []string{"image1=my-image1:*"}, + }, + expected: expected{ + fileOutput: []string{ + "images:", + "- name: image1", + " newName: my-image1", + }}, + }, + { + description: "keep new name and update digest", + given: given{ + args: []string{"image2=*@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3"}, + infileImages: []string{ + "images:", + "- name: image2", + " newName: my-image2", + " digest: sha256:abcdef12345", + }, + }, + expected: expected{ + fileOutput: []string{ + "images:", + "- digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3", + " name: image2", + " newName: my-image2", + }}, + }, + { + description: "keep new name, remove tag, and set digest", + given: given{ + args: []string{"image2=*@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3"}, + infileImages: []string{ + "images:", + "- name: image2", + " newName: my-image2", + " newTag: my-tag", + }, + }, + expected: expected{ + fileOutput: []string{ + "images:", + "- digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3", + " name: image2", + " newName: my-image2", + }}, + }, + { + description: "update new name and keep the digest", + given: given{ + args: []string{"image2=my-image2@*"}, + infileImages: []string{ + "images:", + "- digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3", + " name: image2", + " newName: foo.bar.foo:8800/foo/image1", + }, + }, + expected: expected{ + fileOutput: []string{ + "images:", + "- digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3", + " name: image2", + " newName: my-image2", + }}, + }, } for _, tc := range testCases {