diff --git a/api/builtins/ImageTagTransformer.go b/api/builtins/ImageTagTransformer.go index f7b2f0112..a403699e6 100644 --- a/api/builtins/ImageTagTransformer.go +++ b/api/builtins/ImageTagTransformer.go @@ -8,10 +8,10 @@ import ( "regexp" "strings" - "sigs.k8s.io/kustomize/api/transform" - "sigs.k8s.io/kustomize/api/types" - + "sigs.k8s.io/kustomize/api/filters/imagetag" "sigs.k8s.io/kustomize/api/resmap" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/filtersutil" "sigs.k8s.io/yaml" ) @@ -31,18 +31,18 @@ func (p *ImageTagTransformerPlugin) Config( func (p *ImageTagTransformerPlugin) Transform(m resmap.ResMap) error { for _, r := range m.Resources() { - for _, path := range p.FieldSpecs { - if !r.OrgId().IsSelected(&path.Gvk) { - continue - } - err := transform.MutateField( - r.Map(), path.PathSlice(), false, p.mutateImage) - if err != nil { - return err - } - } - // Kept for backward compatibility - if err := p.findAndReplaceImage(r.Map()); err != nil && r.OrgId().Kind != `CustomResourceDefinition` { + // If you're here because someone expected any field containing + // the string "containers" or "initContainers" to get an image + // update (not just spec/template/spec/containers[], etc.) then + // a code change is needed. See api/filters/imagetag/legacy + // for the start of an implementation that won't use an + // allowlist like FsSlice, and instead walks the object looking + // for fields named containers or initContainers. + err := filtersutil.ApplyToJSON(imagetag.Filter{ + ImageTag: p.ImageTag, + FsSlice: p.FieldSpecs, + }, r) + if err != nil { return err } } diff --git a/api/filters/imagetag/imagetag.go b/api/filters/imagetag/imagetag.go index f20fe7e07..077031754 100644 --- a/api/filters/imagetag/imagetag.go +++ b/api/filters/imagetag/imagetag.go @@ -11,11 +11,17 @@ import ( "sigs.k8s.io/kustomize/kyaml/yaml" ) +// Filter modifies an "image tag", the value used to specify the +// name, tag, version digest etc. of (docker) container images +// used by a pod template. type Filter struct { // imageTag is the tag we want to apply to the inputs + // The name of the image is used as a key, and other fields + // can specify a new name, tag, etc. ImageTag types.Image `json:"imageTag,omitempty" yaml:"imageTag,omitempty"` - // FsSlice contains the FieldSpecs to locate the namespace field + // FsSlice contains the FieldSpecs to locate an image field, + // e.g. Path: "spec/myContainers[]/image" FsSlice types.FsSlice `json:"fieldSpecs,omitempty" yaml:"fieldSpecs,omitempty"` } @@ -27,6 +33,12 @@ func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) { } func (f Filter) filter(node *yaml.RNode) (*yaml.RNode, error) { + // FsSlice is an allowlist, not a denyList, so to deny + // something via configuration a new config mechanism is + // needed. Until then, hardcode it. + if f.isOnDenyList(node) { + return node, nil + } if err := node.PipeE(fsslice.Filter{ FsSlice: f.FsSlice, SetValue: updateImageTagFn(f.ImageTag), @@ -36,6 +48,18 @@ func (f Filter) filter(node *yaml.RNode) (*yaml.RNode, error) { return node, nil } +func (f Filter) isOnDenyList(node *yaml.RNode) bool { + meta, err := node.GetMeta() + if err != nil { + // A missing 'meta' field will cause problems elsewhere; + // ignore it here to keep the signature simple. + return false + } + // Ignore CRDs + // https://github.com/kubernetes-sigs/kustomize/issues/890 + return meta.Kind == `CustomResourceDefinition` +} + func updateImageTagFn(imageTag types.Image) filtersutil.SetFn { return func(node *yaml.RNode) error { return node.PipeE(imageTagUpdater{ diff --git a/api/filters/imagetag/imagetag_test.go b/api/filters/imagetag/imagetag_test.go index a473cc787..c2c43807b 100644 --- a/api/filters/imagetag/imagetag_test.go +++ b/api/filters/imagetag/imagetag_test.go @@ -36,7 +36,7 @@ metadata: name: whatever spec: containers: - - image: theImageShouldNotChangeInACrd + - image: whatever `, filter: Filter{ ImageTag: types.Image{ @@ -139,7 +139,7 @@ spec: - image: nginx:1.2.1 - image: tomcat:1.2.3 template: - spec: + spec: initContainers: - image: nginx:1.2.1 - image: apache:1.2.3 diff --git a/api/konfig/builtinpluginconsts/images.go b/api/konfig/builtinpluginconsts/images.go index 068a2364f..b8d8bf1e3 100644 --- a/api/konfig/builtinpluginconsts/images.go +++ b/api/konfig/builtinpluginconsts/images.go @@ -4,7 +4,15 @@ package builtinpluginconsts const ( - // imageFieldSpecs is left empty since `containers` and `initContainers` - // of *ANY* kind in *ANY* path are builtin supported in code - imagesFieldSpecs = `` + imagesFieldSpecs = ` +images: +- path: spec/containers[]/image + create: true +- path: spec/initContainers[]/image + create: true +- path: spec/template/spec/containers[]/image + create: true +- path: spec/template/spec/initContainers[]/image + create: true +` ) diff --git a/api/krusty/transformersimage_test.go b/api/krusty/transformersimage_test.go index 795be617e..6627de543 100644 --- a/api/krusty/transformersimage_test.go +++ b/api/krusty/transformersimage_test.go @@ -173,6 +173,9 @@ spec: `) } +// The default configuration recognizes image paths starting +// with "spec", not spec2 or spec3, so the latter two specs won't +// have their image entries changed. func TestTransfomersImageDefaultConfig(t *testing.T) { th := kusttest_test.MakeHarness(t) makeTransfomersImageBase(th) @@ -212,25 +215,25 @@ spec2: template: spec: containers: - - image: nginx:v2 + - image: nginx:v1 name: nginx3 - - image: my-nginx:previous + - image: my-nginx:latest name: nginx4 spec3: template: spec: initContainers: - - image: my-postgres:v3 + - image: postgres:alpine-9 name: postgresdb - - image: my-docker@sha256:25a0d4b4 + - image: docker:17-git name: init-docker - - image: myprivaterepohostname:1234/my/image:v1.0.1 + - image: myprivaterepohostname:1234/my/image:latest name: myImage - - image: myprivaterepohostname:1234/my/image:v1.0.1 + - image: myprivaterepohostname:1234/my/image name: myImage2 - image: my-app-image:v1 name: my-app - - image: my-cool-app:latest + - image: gcr.io:8080/my-project/my-cool-app:latest name: my-cool-app `) } @@ -299,11 +302,11 @@ spec3: th.WriteF("/app/base/config/custom.yaml", ` images: - kind: Custom - path: spec/template/spec/myContainers/image + path: spec/template/spec/myContainers[]/image - kind: Custom - path: spec2/template/spec/myContainers/image + path: spec2/template/spec/myContainers[]/image - kind: Custom - path: spec3/template/spec/myInitContainers/image + path: spec3/template/spec/myInitContainers[]/image `) } diff --git a/plugin/builtin/imagetagtransformer/ImageTagTransformer.go b/plugin/builtin/imagetagtransformer/ImageTagTransformer.go index 0ed721192..feb4a41b6 100644 --- a/plugin/builtin/imagetagtransformer/ImageTagTransformer.go +++ b/plugin/builtin/imagetagtransformer/ImageTagTransformer.go @@ -9,10 +9,10 @@ import ( "regexp" "strings" - "sigs.k8s.io/kustomize/api/transform" - "sigs.k8s.io/kustomize/api/types" - + "sigs.k8s.io/kustomize/api/filters/imagetag" "sigs.k8s.io/kustomize/api/resmap" + "sigs.k8s.io/kustomize/api/types" + "sigs.k8s.io/kustomize/kyaml/filtersutil" "sigs.k8s.io/yaml" ) @@ -35,18 +35,18 @@ func (p *plugin) Config( func (p *plugin) Transform(m resmap.ResMap) error { for _, r := range m.Resources() { - for _, path := range p.FieldSpecs { - if !r.OrgId().IsSelected(&path.Gvk) { - continue - } - err := transform.MutateField( - r.Map(), path.PathSlice(), false, p.mutateImage) - if err != nil { - return err - } - } - // Kept for backward compatibility - if err := p.findAndReplaceImage(r.Map()); err != nil && r.OrgId().Kind != `CustomResourceDefinition` { + // If you're here because someone expected any field containing + // the string "containers" or "initContainers" to get an image + // update (not just spec/template/spec/containers[], etc.) then + // a code change is needed. See api/filters/imagetag/legacy + // for the start of an implementation that won't use an + // allowlist like FsSlice, and instead walks the object looking + // for fields named containers or initContainers. + err := filtersutil.ApplyToJSON(imagetag.Filter{ + ImageTag: p.ImageTag, + FsSlice: p.FieldSpecs, + }, r) + if err != nil { return err } } diff --git a/plugin/builtin/imagetagtransformer/ImageTagTransformer_test.go b/plugin/builtin/imagetagtransformer/ImageTagTransformer_test.go index abdb3a656..f9b13f0e5 100644 --- a/plugin/builtin/imagetagtransformer/ImageTagTransformer_test.go +++ b/plugin/builtin/imagetagtransformer/ImageTagTransformer_test.go @@ -22,6 +22,9 @@ metadata: imageTag: name: nginx newTag: v2 +fieldSpecs: +- path: spec/template/spec/containers[]/image +- path: spec/template/spec/initContainers[]/image `, ` group: apps apiVersion: v1 @@ -89,6 +92,9 @@ metadata: imageTag: name: nginx newName: busybox +fieldSpecs: +- path: spec/template/spec/containers[]/image +- path: spec/template/spec/initContainers[]/image `, ` group: apps apiVersion: v1 @@ -158,6 +164,9 @@ imageTag: name: nginx newName: busybox newTag: v2 +fieldSpecs: +- path: spec/template/spec/containers[]/image +- path: spec/template/spec/initContainers[]/image `, ` group: apps apiVersion: v1 @@ -226,6 +235,9 @@ metadata: imageTag: name: nginx Digest: sha256:222222222222222222 +fieldSpecs: +- path: spec/template/spec/containers[]/image +- path: spec/template/spec/initContainers[]/image `, ` group: apps apiVersion: v1 @@ -295,6 +307,9 @@ imageTag: name: nginx newName: busybox Digest: sha256:222222222222222222 +fieldSpecs: +- path: spec/template/spec/containers[]/image +- path: spec/template/spec/initContainers[]/image `, ` group: apps apiVersion: v1 @@ -363,6 +378,11 @@ metadata: imageTag: name: nginx newTag: v2 +fieldSpecs: +- path: spec/template/spec/containers[]/image + create: true +- path: spec/template/spec/initContainers[]/image + create: true `, ` group: apps apiVersion: v1 @@ -384,8 +404,8 @@ metadata: spec: template: spec: - containers: null - initContainers: null + containers: [] + initContainers: [] `) } @@ -402,6 +422,8 @@ metadata: imageTag: name: some.registry.io/my-image newTag: "my-fixed-tag" +fieldSpecs: +- path: spec/template/spec/containers[]/image `, ` group: apps apiVersion: v1 @@ -429,4 +451,4 @@ spec: - image: some.registry.io/my-image:my-fixed-tag name: my-image `) -} \ No newline at end of file +} diff --git a/plugin/builtin/imagetagtransformer/go.mod b/plugin/builtin/imagetagtransformer/go.mod index 6fc060035..b0c09ca34 100644 --- a/plugin/builtin/imagetagtransformer/go.mod +++ b/plugin/builtin/imagetagtransformer/go.mod @@ -4,6 +4,7 @@ go 1.14 require ( sigs.k8s.io/kustomize/api v0.5.1 + sigs.k8s.io/kustomize/kyaml v0.4.1 sigs.k8s.io/yaml v1.2.0 )