Updates in image transformer (#911)

- Decouple `mutateImage` from `updateContainers` to be reused as `mutateFunc`
- Ignore default image transform error for CRD which may contain non-array type `containers` field

Related to #890, #904, fixes #890
This commit is contained in:
Yujun Zhang
2019-03-30 04:11:07 +08:00
committed by Jingfang Liu
parent 21a0cba43e
commit 2490e605c3
3 changed files with 150 additions and 19 deletions

View File

@@ -320,3 +320,64 @@ spec:
action: makehoney
`)
}
func TestCrdWithContainers(t *testing.T) {
th := NewKustTestHarness(t, "/app/crd/containers")
th.writeK("/app/crd/containers", `
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- crd.yaml
images:
- name: test/test
newName: registry.gitlab.com/test
newTag: latest
`)
th.writeF("/app/crd/containers/crd.yaml", `
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: crontabs.stable.example.com
spec:
group: stable.example.com
scope: Namespaced
names:
plural: crontabs
singular: crontab
kind: CronTab
shortNames:
- ct
validation:
openAPIV3Schema:
properties:
spec:
containers:
description: Containers allows injecting additional containers
`)
m, err := th.makeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.assertActualEqualsExpected(m, `
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: crontabs.stable.example.com
spec:
group: stable.example.com
names:
kind: CronTab
plural: crontabs
shortNames:
- ct
singular: crontab
scope: Namespaced
validation:
openAPIV3Schema:
properties:
spec:
containers:
description: Containers allows injecting additional containers
`)
}

View File

@@ -233,11 +233,11 @@ spec3:
th.writeF("/app/base/config/custom.yaml", `
images:
- kind: Custom
path: spec/template/spec/myContainers
path: spec/template/spec/myContainers/image
- kind: Custom
path: spec2/template/spec/myContainers
path: spec2/template/spec/myContainers/image
- kind: Custom
path: spec3/template/spec/myInitContainers
path: spec3/template/spec/myInitContainers/image
`)
}
func TestTransfomersImageCustomConfig(t *testing.T) {
@@ -283,3 +283,56 @@ spec3:
name: my-cool-app
`)
}
func makeTransfomersImageKnativeBase(th *KustTestHarness) {
th.writeK("/app/base", `
resources:
- knative.yaml
configurations:
- config/knative.yaml
images:
- name: solsa-echo
newTag: foo
`)
th.writeF("/app/base/knative.yaml", `
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: echo
spec:
runLatest:
configuration:
revisionTemplate:
spec:
container:
image: solsa-echo
`)
th.writeF("/app/base/config/knative.yaml", `
images:
- path: spec/runLatest/configuration/revisionTemplate/spec/container/image
apiVersion: serving.knative.dev/v1alpha1
kind: Service
`)
}
func TestTransfomersImageKnativeConfig(t *testing.T) {
th := NewKustTestHarness(t, "/app/base")
makeTransfomersImageKnativeBase(th)
m, err := th.makeKustTarget().MakeCustomizedResMap()
if err != nil {
t.Fatalf("Err: %v", err)
}
th.assertActualEqualsExpected(m, `
apiVersion: serving.knative.dev/v1alpha1
kind: Service
metadata:
name: echo
spec:
runLatest:
configuration:
revisionTemplate:
spec:
container:
image: solsa-echo:foo
`)
}

View File

@@ -50,20 +50,44 @@ func (pt *imageTransformer) Transform(m resmap.ResMap) error {
if !id.Gvk().IsSelected(&path.Gvk) {
continue
}
err := mutateField(objMap, path.PathSlice(), false, pt.updateContainers)
err := mutateField(objMap, path.PathSlice(), false, pt.mutateImage)
if err != nil {
return err
}
}
// Keep for backward compatibility
err := pt.findAndReplaceImage(objMap)
if err != nil {
// Kept for backward compatibility
if err := pt.findAndReplaceImage(objMap); err != nil && id.Gvk().Kind != `CustomResourceDefinition` {
return err
}
}
return nil
}
func (pt *imageTransformer) mutateImage(in interface{}) (interface{}, error) {
image, ok := in.(string)
if !ok {
return nil, fmt.Errorf("image path is not of type string but %T", in)
}
for _, img := range pt.images {
if !isImageMatched(image, img.Name) {
continue
}
name, tag := split(image)
if img.NewName != "" {
name = img.NewName
}
if img.NewTag != "" {
tag = ":" + img.NewTag
}
if img.Digest != "" {
tag = "@" + img.Digest
}
return name + tag, nil
}
return image, nil
}
/*
findAndReplaceImage replaces the image name and tags inside one object
It searches the object for container session
@@ -76,8 +100,7 @@ func (pt *imageTransformer) findAndReplaceImage(obj map[string]interface{}) erro
for _, path := range paths {
containers, found := obj[path]
if found {
_, err := pt.updateContainers(containers)
if err != nil {
if _, err := pt.updateContainers(containers); err != nil {
return err
}
updated = true
@@ -106,17 +129,11 @@ func (pt *imageTransformer) updateContainers(in interface{}) (interface{}, error
if !isImageMatched(imageName, img.Name) {
continue
}
name, tag := split(imageName)
if img.NewName != "" {
name = img.NewName
newImage, err := pt.mutateImage(imageName)
if err != nil {
return nil, err
}
if img.NewTag != "" {
tag = ":" + img.NewTag
}
if img.Digest != "" {
tag = "@" + img.Digest
}
container["image"] = name + tag
container["image"] = newImage
break
}
}