Files
kustomize/api/krusty/multiplepatch_test.go
2021-03-17 06:35:30 -07:00

1229 lines
23 KiB
Go

// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package krusty_test
import (
"testing"
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
)
func TestRemoveEmptyDirWithNullFieldInSmp(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK(".", `
resources:
- deployment.yaml
patchesStrategicMerge:
- patch.yaml
`)
th.WriteF("deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
volumes:
- name: fancyDisk
emptyDir: {}
`)
th.WriteF("patch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
volumes:
- name: fancyDisk
emptyDir: null
`)
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
volumes:
- name: fancyDisk
`)
}
func TestRemoveEmptyDirAddPersistentDisk(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK(".", `
resources:
- deployment.yaml
patchesStrategicMerge:
- patch.yaml
`)
th.WriteF("deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
volumes:
- name: fancyDisk
emptyDir: {}
`)
th.WriteF("patch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
volumes:
- name: fancyDisk
emptyDir: null
gcePersistentDisk:
pdName: fancyDisk
`)
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
volumes:
- gcePersistentDisk:
pdName: fancyDisk
name: fancyDisk
`)
}
func TestVolumeRemoveEmptyDirInOverlay(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK("base", `
resources:
- deployment.yaml
configMapGenerator:
- name: baseCm
literals:
- foo=bar
`)
th.WriteF("base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: fancyDisk
mountPath: /tmp/ps
volumes:
- name: fancyDisk
emptyDir: {}
- configMap:
name: baseCm
name: baseCm
`)
m := th.Run("base", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: fancyDisk
volumes:
- emptyDir: {}
name: fancyDisk
- configMap:
name: baseCm-798k5k7g9f
name: baseCm
---
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
name: baseCm-798k5k7g9f
`)
th.WriteK("overlay", `
patchesStrategicMerge:
- patch.yaml
resources:
- ../base
configMapGenerator:
- name: overlayCm
literals:
- hello=world
`)
th.WriteF("overlay/patch.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
volumes:
- name: fancyDisk
emptyDir: null
gcePersistentDisk:
pdName: fancyDisk
- configMap:
name: overlayCm
name: overlayCm
`)
m = th.Run("overlay", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: fancyDisk
volumes:
- gcePersistentDisk:
pdName: fancyDisk
name: fancyDisk
- configMap:
name: overlayCm-dc6fm46dhm
name: overlayCm
- configMap:
name: baseCm-798k5k7g9f
name: baseCm
---
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
name: baseCm-798k5k7g9f
---
apiVersion: v1
data:
hello: world
kind: ConfigMap
metadata:
name: overlayCm-dc6fm46dhm
`)
}
// Goal is to remove " emptyDir: {}" with a patch.
func TestRemoveEmptyDirWithPatchesAtSameLevel(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK("base", `
resources:
- deployment.yaml
`)
th.WriteF("base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: nginx
- name: sidecar
image: sidecar:latest
volumes:
- name: nginx-persistent-storage
emptyDir: {}
`)
th.WriteK("overlay", `
patchesStrategicMerge:
- deployment-patch1.yaml
- deployment-patch2.yaml
resources:
- ../base
`)
th.WriteF("overlay/deployment-patch1.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
volumes:
- name: nginx-persistent-storage
emptyDir: null
gcePersistentDisk:
pdName: nginx-persistent-storage
`)
th.WriteF("overlay/deployment-patch2.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- image: nginx
name: nginx
env:
- name: ANOTHERENV
value: FOO
volumes:
- name: nginx-persistent-storage
`)
opts := th.MakeDefaultOptions()
m := th.Run("overlay", opts)
th.AssertActualEqualsExpected(
m, `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- env:
- name: ANOTHERENV
value: FOO
image: nginx
name: nginx
- image: sidecar:latest
name: sidecar
volumes:
- gcePersistentDisk:
pdName: nginx-persistent-storage
name: nginx-persistent-storage
`)
}
func TestSimpleMultiplePatches(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK("base", `
namePrefix: b-
commonLabels:
team: foo
resources:
- deployment.yaml
- service.yaml
configMapGenerator:
- name: configmap-in-base
literals:
- foo=bar
`)
th.WriteF("base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: nginx-persistent-storage
mountPath: /tmp/ps
- name: sidecar
image: sidecar:latest
volumes:
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
th.WriteF("base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
`)
th.WriteK("overlay", `
namePrefix: a-
commonLabels:
env: staging
patchesStrategicMerge:
- deployment-patch1.yaml
- deployment-patch2.yaml
resources:
- ../base
configMapGenerator:
- name: configmap-in-overlay
literals:
- hello=world
`)
th.WriteF("overlay/deployment-patch1.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: nginx:latest
env:
- name: ENVKEY
value: ENVVALUE
volumes:
- name: nginx-persistent-storage
gcePersistentDisk:
pdName: nginx-persistent-storage
- configMap:
name: configmap-in-overlay
name: configmap-in-overlay
`)
th.WriteF("overlay/deployment-patch2.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
env:
- name: ANOTHERENV
value: FOO
`)
m := th.Run("overlay", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
env: staging
team: foo
name: a-b-nginx
spec:
selector:
matchLabels:
env: staging
team: foo
template:
metadata:
labels:
env: staging
team: foo
spec:
containers:
- env:
- name: ANOTHERENV
value: FOO
- name: ENVKEY
value: ENVVALUE
image: nginx:latest
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
- image: sidecar:latest
name: sidecar
volumes:
- gcePersistentDisk:
pdName: nginx-persistent-storage
name: nginx-persistent-storage
- configMap:
name: a-configmap-in-overlay-dc6fm46dhm
name: configmap-in-overlay
- configMap:
name: a-b-configmap-in-base-798k5k7g9f
name: configmap-in-base
---
apiVersion: v1
kind: Service
metadata:
labels:
env: staging
team: foo
name: a-b-nginx
spec:
ports:
- port: 80
selector:
env: staging
team: foo
---
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
labels:
env: staging
team: foo
name: a-b-configmap-in-base-798k5k7g9f
---
apiVersion: v1
data:
hello: world
kind: ConfigMap
metadata:
labels:
env: staging
name: a-configmap-in-overlay-dc6fm46dhm
`)
}
func makeCommonFilesForMultiplePatchTests(th kusttest_test.Harness) {
th.WriteK("base", `
namePrefix: team-foo-
commonLabels:
app: mynginx
org: example.com
team: foo
commonAnnotations:
note: This is a test annotation
resources:
- deployment.yaml
- service.yaml
configMapGenerator:
- name: configmap-in-base
literals:
- foo=bar
`)
th.WriteF("base/deployment.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: nginx-persistent-storage
mountPath: /tmp/ps
- name: sidecar
image: sidecar:latest
volumes:
- configMap:
name: configmap-in-base
name: configmap-in-base
`)
th.WriteF("base/service.yaml", `
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
selector:
app: nginx
`)
th.WriteK("overlay/staging", `
namePrefix: staging-
commonLabels:
env: staging
patchesStrategicMerge:
- deployment-patch1.yaml
- deployment-patch2.yaml
resources:
- ../../base
configMapGenerator:
- name: configmap-in-overlay
literals:
- hello=world
`)
}
func TestMultiplePatchesNoConflict(t *testing.T) {
th := kusttest_test.MakeHarness(t)
makeCommonFilesForMultiplePatchTests(th)
th.WriteF("overlay/staging/deployment-patch1.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
image: nginx:latest
env:
- name: ENVKEY
value: ENVVALUE
volumes:
- name: nginx-persistent-storage
gcePersistentDisk:
pdName: nginx-persistent-storage
- configMap:
name: configmap-in-overlay
name: configmap-in-overlay
`)
th.WriteF("overlay/staging/deployment-patch2.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
env:
- name: ANOTHERENV
value: FOO
`)
m := th.Run("overlay/staging", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-nginx
spec:
selector:
matchLabels:
app: mynginx
env: staging
org: example.com
team: foo
template:
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
spec:
containers:
- env:
- name: ANOTHERENV
value: FOO
- name: ENVKEY
value: ENVVALUE
image: nginx:latest
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
- image: sidecar:latest
name: sidecar
volumes:
- gcePersistentDisk:
pdName: nginx-persistent-storage
name: nginx-persistent-storage
- configMap:
name: staging-configmap-in-overlay-dc6fm46dhm
name: configmap-in-overlay
- configMap:
name: staging-team-foo-configmap-in-base-798k5k7g9f
name: configmap-in-base
---
apiVersion: v1
kind: Service
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-nginx
spec:
ports:
- port: 80
selector:
app: mynginx
env: staging
org: example.com
team: foo
---
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-configmap-in-base-798k5k7g9f
---
apiVersion: v1
data:
hello: world
kind: ConfigMap
metadata:
labels:
env: staging
name: staging-configmap-in-overlay-dc6fm46dhm
`)
}
func TestNonCommutablePatches(t *testing.T) {
th := kusttest_test.MakeHarness(t)
makeCommonFilesForMultiplePatchTests(th)
th.WriteF("overlay/staging/deployment-patch1.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
env:
- name: ENABLE_FEATURE_FOO
value: TRUE
volumes:
- name: nginx-persistent-storage
gcePersistentDisk:
pdName: nginx-persistent-storage
- configMap:
name: configmap-in-overlay
name: configmap-in-overlay
`)
th.WriteF("overlay/staging/deployment-patch2.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
env:
- name: ENABLE_FEATURE_FOO
value: FALSE
`)
// kyaml doesn't try to detect conflicts in patches
// (so ENABLE_FEATURE_FOO FALSE wins).
m := th.Run("overlay/staging", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-nginx
spec:
selector:
matchLabels:
app: mynginx
env: staging
org: example.com
team: foo
template:
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
spec:
containers:
- env:
- name: ENABLE_FEATURE_FOO
value: false
image: nginx
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
- image: sidecar:latest
name: sidecar
volumes:
- gcePersistentDisk:
pdName: nginx-persistent-storage
name: nginx-persistent-storage
- configMap:
name: staging-configmap-in-overlay-dc6fm46dhm
name: configmap-in-overlay
- configMap:
name: staging-team-foo-configmap-in-base-798k5k7g9f
name: configmap-in-base
---
apiVersion: v1
kind: Service
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-nginx
spec:
ports:
- port: 80
selector:
app: mynginx
env: staging
org: example.com
team: foo
---
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-configmap-in-base-798k5k7g9f
---
apiVersion: v1
data:
hello: world
kind: ConfigMap
metadata:
labels:
env: staging
name: staging-configmap-in-overlay-dc6fm46dhm
`)
}
func TestMultiplePatchesWithOnePatchDeleteDirective(t *testing.T) {
additivePatch := `apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- name: nginx
env:
- name: SOME_NAME
value: somevalue
`
deletePatch := `apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- $patch: delete
name: sidecar
`
cases := map[string]struct {
patch1 string
patch2 string
expectError bool
}{
"Patch with delete directive first": {
patch1: deletePatch,
patch2: additivePatch,
},
"Patch with delete directive second": {
patch1: additivePatch,
patch2: deletePatch,
},
}
for name := range cases {
c := cases[name]
t.Run(name, func(t *testing.T) {
th := kusttest_test.MakeHarness(t)
makeCommonFilesForMultiplePatchTests(th)
th.WriteF("overlay/staging/deployment-patch1.yaml", c.patch1)
th.WriteF("overlay/staging/deployment-patch2.yaml", c.patch2)
m := th.Run("overlay/staging", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-nginx
spec:
selector:
matchLabels:
app: mynginx
env: staging
org: example.com
team: foo
template:
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
spec:
containers:
- env:
- name: SOME_NAME
value: somevalue
image: nginx
name: nginx
volumeMounts:
- mountPath: /tmp/ps
name: nginx-persistent-storage
volumes:
- configMap:
name: staging-team-foo-configmap-in-base-798k5k7g9f
name: configmap-in-base
---
apiVersion: v1
kind: Service
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-nginx
spec:
ports:
- port: 80
selector:
app: mynginx
env: staging
org: example.com
team: foo
---
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-configmap-in-base-798k5k7g9f
---
apiVersion: v1
data:
hello: world
kind: ConfigMap
metadata:
labels:
env: staging
name: staging-configmap-in-overlay-dc6fm46dhm
`)
})
}
}
func TestMultiplePatchesBothWithPatchDeleteDirective(t *testing.T) {
th := kusttest_test.MakeHarness(t)
makeCommonFilesForMultiplePatchTests(th)
th.WriteF("overlay/staging/deployment-patch1.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- $patch: delete
name: sidecar
`)
th.WriteF("overlay/staging/deployment-patch2.yaml", `
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
spec:
containers:
- $patch: delete
name: nginx
`)
// kyaml doesn't fail on conflicts in patches; both containers
// (nginx and sidecar) are deleted per this patching instruction.
m := th.Run("overlay/staging", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-nginx
spec:
selector:
matchLabels:
app: mynginx
env: staging
org: example.com
team: foo
template:
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
spec:
containers: []
volumes:
- configMap:
name: staging-team-foo-configmap-in-base-798k5k7g9f
name: configmap-in-base
---
apiVersion: v1
kind: Service
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-nginx
spec:
ports:
- port: 80
selector:
app: mynginx
env: staging
org: example.com
team: foo
---
apiVersion: v1
data:
foo: bar
kind: ConfigMap
metadata:
annotations:
note: This is a test annotation
labels:
app: mynginx
env: staging
org: example.com
team: foo
name: staging-team-foo-configmap-in-base-798k5k7g9f
---
apiVersion: v1
data:
hello: world
kind: ConfigMap
metadata:
labels:
env: staging
name: staging-configmap-in-overlay-dc6fm46dhm
`)
}
// test for #3513
func TestSmpWithDifferentKeysOnDifferentPorts(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK(".", `
resources:
- resource.yaml
patches:
- path: patch.yaml
target:
kind: StatefulSet
name: myapp
`)
th.WriteF("resource.yaml", `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: myapp
spec:
template:
spec:
containers:
- name: consul
image: "dashicorp/consul:1.9.1"
ports:
- containerPort: 8500
name: http
- containerPort: 8501
name: https
- containerPort: 8301
protocol: "TCP"
name: serflan-tcp
- containerPort: 8301
protocol: "UDP"
name: serflan-udp
- containerPort: 8302
name: serfwan
- containerPort: 8300
name: server
- containerPort: 8600
name: dns-tcp
protocol: "TCP"
- containerPort: 8600
name: dns-udp
protocol: "UDP"`)
th.WriteF("patch.yaml", `
kind: StatefulSet
metadata:
name: myapp
labels:
test: label
`)
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: apps/v1
kind: StatefulSet
metadata:
labels:
test: label
name: myapp
spec:
template:
spec:
containers:
- image: dashicorp/consul:1.9.1
name: consul
ports:
- containerPort: 8301
name: serflan-tcp
protocol: TCP
- containerPort: 8301
name: serflan-udp
protocol: UDP
- containerPort: 8600
name: dns-tcp
protocol: TCP
- containerPort: 8600
name: dns-udp
protocol: UDP
- containerPort: 8500
name: http
- containerPort: 8501
name: https
- containerPort: 8302
name: serfwan
- containerPort: 8300
name: server
`)
}
// test for #3616
func TestSmpDeleteOnResource(t *testing.T) {
th := kusttest_test.MakeHarness(t)
th.WriteK(".", `
resources:
- workloads.yaml
patches:
- patch: |
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: rule1
$patch: delete
`)
th.WriteF("workloads.yaml", `
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
labels:
role: alert-rules
name: rule1
spec:
groups:
- name: rabbitmq.rules
---
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
labels:
role: alert-rules
name: rule2
spec:
groups:
- name: rabbitmq.rules
`)
m := th.Run(".", th.MakeDefaultOptions())
th.AssertActualEqualsExpected(m, `
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
labels:
role: alert-rules
name: rule2
spec:
groups:
- name: rabbitmq.rules
`)
}