Merge pull request #841 from yujunz/transformers/image

Support custom configuration for image transformer
This commit is contained in:
Kubernetes Prow Robot
2019-03-19 14:08:22 -07:00
committed by GitHub
6 changed files with 172 additions and 13 deletions

View File

@@ -312,7 +312,7 @@ func (kt *KustTarget) newTransformer(
return nil, err return nil, err
} }
r = append(r, t) r = append(r, t)
t, err = transformers.NewImageTransformer(kt.kustomization.Images) t, err = transformers.NewImageTransformer(kt.kustomization.Images, tConfig.Images)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@@ -168,3 +168,118 @@ spec3:
name: my-cool-app 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
`)
}

View File

@@ -31,6 +31,7 @@ func GetDefaultFieldSpecs() []byte {
[]byte(namespaceFieldSpecs), []byte(namespaceFieldSpecs),
[]byte(varReferenceFieldSpecs), []byte(varReferenceFieldSpecs),
[]byte(nameReferenceFieldSpecs), []byte(nameReferenceFieldSpecs),
[]byte(imagesFieldSpecs),
} }
return bytes.Join(configData, []byte("\n")) return bytes.Join(configData, []byte("\n"))
} }
@@ -45,5 +46,6 @@ func GetDefaultFieldSpecsAsMap() map[string]string {
result["namespace"] = namespaceFieldSpecs result["namespace"] = namespaceFieldSpecs
result["varreference"] = varReferenceFieldSpecs result["varreference"] = varReferenceFieldSpecs
result["namereference"] = nameReferenceFieldSpecs result["namereference"] = nameReferenceFieldSpecs
result["images"] = imagesFieldSpecs
return result return result
} }

View File

@@ -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 = ``
)

View File

@@ -34,6 +34,7 @@ type TransformerConfig struct {
CommonAnnotations fsSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"` CommonAnnotations fsSlice `json:"commonAnnotations,omitempty" yaml:"commonAnnotations,omitempty"`
NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"` NameReference nbrSlice `json:"nameReference,omitempty" yaml:"nameReference,omitempty"`
VarReference fsSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"` VarReference fsSlice `json:"varReference,omitempty" yaml:"varReference,omitempty"`
Images fsSlice `json:"images,omitempty" yaml:"images,omitempty"`
} }
// MakeEmptyConfig returns an empty TransformerConfig object // MakeEmptyConfig returns an empty TransformerConfig object
@@ -59,6 +60,7 @@ func (t *TransformerConfig) sortFields() {
sort.Sort(t.CommonAnnotations) sort.Sort(t.CommonAnnotations)
sort.Sort(t.NameReference) sort.Sort(t.NameReference)
sort.Sort(t.VarReference) sort.Sort(t.VarReference)
sort.Sort(t.Images)
} }
// AddPrefixFieldSpec adds a FieldSpec to NamePrefix // AddPrefixFieldSpec adds a FieldSpec to NamePrefix
@@ -129,6 +131,10 @@ func (t *TransformerConfig) Merge(input *TransformerConfig) (
if err != nil { if err != nil {
return nil, err return nil, err
} }
merged.Images, err = t.Images.mergeAll(input.Images)
if err != nil {
return nil, err
}
merged.sortFields() merged.sortFields()
return merged, nil return merged, nil
} }

View File

@@ -23,27 +23,40 @@ import (
"sigs.k8s.io/kustomize/pkg/image" "sigs.k8s.io/kustomize/pkg/image"
"sigs.k8s.io/kustomize/pkg/resmap" "sigs.k8s.io/kustomize/pkg/resmap"
"sigs.k8s.io/kustomize/pkg/transformers/config"
) )
// imageTransformer replace image names and tags // imageTransformer replace image names and tags
type imageTransformer struct { type imageTransformer struct {
images []image.Image images []image.Image
fieldSpecs []config.FieldSpec
} }
var _ Transformer = &imageTransformer{} var _ Transformer = &imageTransformer{}
// NewImageTransformer constructs an imageTransformer. // NewImageTransformer constructs an imageTransformer.
func NewImageTransformer(slice []image.Image) (Transformer, error) { func NewImageTransformer(slice []image.Image, fs []config.FieldSpec) (Transformer, error) {
return &imageTransformer{slice}, nil return &imageTransformer{slice, fs}, nil
} }
// Transform finds the matching images and replaces name, tag and/or digest // 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 { if len(pt.images) == 0 {
return nil return nil
} }
for _, res := range resources { for id := range m {
err := pt.findAndReplaceImage(res.Map()) 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 { if err != nil {
return err return err
} }
@@ -61,9 +74,9 @@ func (pt *imageTransformer) findAndReplaceImage(obj map[string]interface{}) erro
paths := []string{"containers", "initContainers"} paths := []string{"containers", "initContainers"}
found := false found := false
for _, path := range paths { for _, path := range paths {
_, found = obj[path] containers, found := obj[path]
if found { if found {
err := pt.updateContainers(obj, path) _, err := pt.updateContainers(containers)
if err != nil { if err != nil {
return err return err
} }
@@ -75,10 +88,10 @@ func (pt *imageTransformer) findAndReplaceImage(obj map[string]interface{}) erro
return nil return nil
} }
func (pt *imageTransformer) updateContainers(obj map[string]interface{}, path string) error { func (pt *imageTransformer) updateContainers(in interface{}) (interface{}, error) {
containers, ok := obj[path].([]interface{}) containers, ok := in.([]interface{})
if !ok { 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 { for i := range containers {
container := containers[i].(map[string]interface{}) container := containers[i].(map[string]interface{})
@@ -106,7 +119,7 @@ func (pt *imageTransformer) updateContainers(obj map[string]interface{}, path st
break break
} }
} }
return nil return containers, nil
} }
func (pt *imageTransformer) findContainers(obj map[string]interface{}) error { func (pt *imageTransformer) findContainers(obj map[string]interface{}) error {