diff --git a/pkg/target/kusttarget.go b/pkg/target/kusttarget.go index 6a6eb952b..2232a1e80 100644 --- a/pkg/target/kusttarget.go +++ b/pkg/target/kusttarget.go @@ -312,7 +312,7 @@ func (kt *KustTarget) newTransformer( return nil, err } r = append(r, t) - t, err = transformers.NewImageTransformer(kt.kustomization.Images) + t, err = transformers.NewImageTransformer(kt.kustomization.Images, tConfig.Images) if err != nil { return nil, err } diff --git a/pkg/target/transformersimage_test.go b/pkg/target/transformersimage_test.go index 7d09bdf49..3f12e0cb7 100644 --- a/pkg/target/transformersimage_test.go +++ b/pkg/target/transformersimage_test.go @@ -168,3 +168,118 @@ spec3: name: my-cool-app `) } + +func makeTransfomersImageCustomBase(th *KustTestHarness) { + th.writeK("/app/base", ` +resources: +- custom.yaml +configurations: +- config/custom.yaml +images: +- name: nginx + newTag: v2 +- name: my-nginx + newTag: previous +- name: myprivaterepohostname:1234/my/image + newTag: v1.0.1 +- name: foobar + digest: sha256:24a0c4b4 +- name: alpine + newName: myprivaterepohostname:1234/my/cool-alpine +- name: gcr.io:8080/my-project/my-cool-app + newName: my-cool-app +- name: postgres + newName: my-postgres + newTag: v3 +- name: docker + newName: my-docker + digest: sha256:25a0d4b4 +`) + th.writeF("/app/base/custom.yaml", ` +kind: customKind +metadata: + name: custom +spec: + template: + spec: + myContainers: + - name: ngnix1 + image: nginx +spec2: + template: + spec: + myContainers: + - name: nginx3 + image: nginx:v1 + - name: nginx4 + image: my-nginx:latest +spec3: + template: + spec: + myInitContainers: + - name: postgresdb + image: postgres:alpine-9 + - name: init-docker + image: docker:17-git + - name: myImage + image: myprivaterepohostname:1234/my/image:latest + - name: myImage2 + image: myprivaterepohostname:1234/my/image + - name: my-app + image: my-app-image:v1 + - name: my-cool-app + image: gcr.io:8080/my-project/my-cool-app:latest +`) + th.writeF("/app/base/config/custom.yaml", ` +images: +- kind: Custom + path: spec/template/spec/myContainers +- kind: Custom + path: spec2/template/spec/myContainers +- kind: Custom + path: spec3/template/spec/myInitContainers +`) +} +func TestTransfomersImageCustomConfig(t *testing.T) { + th := NewKustTestHarness(t, "/app/base") + makeTransfomersImageCustomBase(th) + m, err := th.makeKustTarget().MakeCustomizedResMap() + if err != nil { + t.Fatalf("Err: %v", err) + } + th.assertActualEqualsExpected(m, ` +kind: customKind +metadata: + name: custom +spec: + template: + spec: + myContainers: + - image: nginx + name: ngnix1 +spec2: + template: + spec: + myContainers: + - image: nginx:v1 + name: nginx3 + - image: my-nginx:latest + name: nginx4 +spec3: + template: + spec: + myInitContainers: + - image: postgres:alpine-9 + name: postgresdb + - image: docker:17-git + name: init-docker + - image: myprivaterepohostname:1234/my/image:latest + name: myImage + - image: myprivaterepohostname:1234/my/image + name: myImage2 + - image: my-app-image:v1 + name: my-app + - image: gcr.io:8080/my-project/my-cool-app:latest + name: my-cool-app +`) +} diff --git a/pkg/transformers/config/defaultconfig/defaultconfig.go b/pkg/transformers/config/defaultconfig/defaultconfig.go index d96639a8a..d34d9a934 100644 --- a/pkg/transformers/config/defaultconfig/defaultconfig.go +++ b/pkg/transformers/config/defaultconfig/defaultconfig.go @@ -31,6 +31,7 @@ func GetDefaultFieldSpecs() []byte { []byte(namespaceFieldSpecs), []byte(varReferenceFieldSpecs), []byte(nameReferenceFieldSpecs), + []byte(imagesFieldSpecs), } return bytes.Join(configData, []byte("\n")) } @@ -45,5 +46,6 @@ func GetDefaultFieldSpecsAsMap() map[string]string { result["namespace"] = namespaceFieldSpecs result["varreference"] = varReferenceFieldSpecs result["namereference"] = nameReferenceFieldSpecs + result["images"] = imagesFieldSpecs return result } diff --git a/pkg/transformers/config/defaultconfig/images.go b/pkg/transformers/config/defaultconfig/images.go new file mode 100644 index 000000000..7612b616c --- /dev/null +++ b/pkg/transformers/config/defaultconfig/images.go @@ -0,0 +1,23 @@ +/* +Copyright 2019 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package defaultconfig + +const ( + // imageFieldSpecs is left empty since `containers` and `initContainers` + // of *ANY* kind in *ANY* path are builtin supported in code + imagesFieldSpecs = `` +) diff --git a/pkg/transformers/config/transformerconfig.go b/pkg/transformers/config/transformerconfig.go index 556f0b814..a00c6da66 100644 --- a/pkg/transformers/config/transformerconfig.go +++ b/pkg/transformers/config/transformerconfig.go @@ -34,6 +34,7 @@ type TransformerConfig struct { CommonAnnotations fsSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"` NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"` VarReference fsSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"` + Images fsSlice `json:"images,omitempty" yaml:"images,omitempty"` } // MakeEmptyConfig returns an empty TransformerConfig object @@ -59,6 +60,7 @@ func (t *TransformerConfig) sortFields() { sort.Sort(t.CommonAnnotations) sort.Sort(t.NameReference) sort.Sort(t.VarReference) + sort.Sort(t.Images) } // AddPrefixFieldSpec adds a FieldSpec to NamePrefix @@ -129,6 +131,10 @@ func (t *TransformerConfig) Merge(input *TransformerConfig) ( if err != nil { return nil, err } + merged.Images, err = t.Images.mergeAll(input.Images) + if err != nil { + return nil, err + } merged.sortFields() return merged, nil } diff --git a/pkg/transformers/image.go b/pkg/transformers/image.go index 2e0797694..ba8dbab50 100644 --- a/pkg/transformers/image.go +++ b/pkg/transformers/image.go @@ -23,27 +23,40 @@ import ( "sigs.k8s.io/kustomize/pkg/image" "sigs.k8s.io/kustomize/pkg/resmap" + "sigs.k8s.io/kustomize/pkg/transformers/config" ) // imageTransformer replace image names and tags type imageTransformer struct { - images []image.Image + images []image.Image + fieldSpecs []config.FieldSpec } var _ Transformer = &imageTransformer{} // NewImageTransformer constructs an imageTransformer. -func NewImageTransformer(slice []image.Image) (Transformer, error) { - return &imageTransformer{slice}, nil +func NewImageTransformer(slice []image.Image, fs []config.FieldSpec) (Transformer, error) { + return &imageTransformer{slice, fs}, nil } // Transform finds the matching images and replaces name, tag and/or digest -func (pt *imageTransformer) Transform(resources resmap.ResMap) error { +func (pt *imageTransformer) Transform(m resmap.ResMap) error { if len(pt.images) == 0 { return nil } - for _, res := range resources { - err := pt.findAndReplaceImage(res.Map()) + for id := range m { + objMap := m[id].Map() + for _, path := range pt.fieldSpecs { + if !id.Gvk().IsSelected(&path.Gvk) { + continue + } + err := mutateField(objMap, path.PathSlice(), false, pt.updateContainers) + if err != nil { + return err + } + } + // Keep for backward compatibility + err := pt.findAndReplaceImage(objMap) if err != nil { return err } @@ -61,9 +74,9 @@ func (pt *imageTransformer) findAndReplaceImage(obj map[string]interface{}) erro paths := []string{"containers", "initContainers"} found := false for _, path := range paths { - _, found = obj[path] + containers, found := obj[path] if found { - err := pt.updateContainers(obj, path) + _, err := pt.updateContainers(containers) if err != nil { return err } @@ -75,10 +88,10 @@ func (pt *imageTransformer) findAndReplaceImage(obj map[string]interface{}) erro return nil } -func (pt *imageTransformer) updateContainers(obj map[string]interface{}, path string) error { - containers, ok := obj[path].([]interface{}) +func (pt *imageTransformer) updateContainers(in interface{}) (interface{}, error) { + containers, ok := in.([]interface{}) if !ok { - return fmt.Errorf("containers path is not of type []interface{} but %T", obj[path]) + return nil, fmt.Errorf("containers path is not of type []interface{} but %T", in) } for i := range containers { container := containers[i].(map[string]interface{}) @@ -106,7 +119,7 @@ func (pt *imageTransformer) updateContainers(obj map[string]interface{}, path st break } } - return nil + return containers, nil } func (pt *imageTransformer) findContainers(obj map[string]interface{}) error {