Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add complex overlay composition test #1297

Merged
merged 1 commit into from
Jul 2, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
339 changes: 339 additions & 0 deletions pkg/target/complexcomposition_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,339 @@
// Copyright 2019 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0

package target_test

import (
"strings"
"testing"

"sigs.k8s.io/kustomize/v3/pkg/kusttest"
)

// Base
// ----
const baseKustomization = `
resources:
- statefulset.yaml
`

const baseStatefulSet = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
serviceName: my-svc
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-image
volumeClaimTemplates:
- spec:
storageClassName: default
`

// Storage overlay
// ---------------
const storageKustomization = `
resources:
- ../base
patchesJson6902:
- target:
group: apps
version: v1
kind: StatefulSet
name: my-sts
path: sts-patch.json
`

const patchJsonPVCTemplate = `
[{"op": "replace", "path": "/spec/volumeClaimTemplates/0/spec/storageClassName", "value": "my-sc"}]
`

// Config overlay
// --------------
const configKustomization = `
resources:
- ../base
configMapGenerator:
- name: my-config
literals:
- MY_ENV=foo
generatorOptions:
disableNameSuffixHash: true
patchesStrategicMerge:
- sts-patch.yaml
`

const patchEnvFromConfig = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
template:
spec:
containers:
- name: app
envFrom:
- configMapRef:
name: my-config
`

// Tolerations overlay
// -------------------
const tolerationsKustomization = `
resources:
- ../base
patchesStrategicMerge:
- sts-patch.yaml
`

const patchTolerations = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
template:
spec:
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
tolerationSeconds: 30
`

// HTTPS overlay
// -------------
const httpsKustomization = `
resources:
- ../base
- https-svc.yaml
patchesStrategicMerge:
- sts-patch.yaml
`

const patchService = `
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
serviceName: my-https-svc
`

const httpsService = `
apiVersion: v1
kind: Service
metadata:
name: my-https-svc
spec:
ports:
- port: 443
protocol: TCP
name: https
selector:
app: my-app
`

func writeStatefulSetBase(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/base", baseKustomization)
th.WriteF("/app/base/statefulset.yaml", baseStatefulSet)
}

func writeHTTPSOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/https", httpsKustomization)
th.WriteF("/app/https/https-svc.yaml", httpsService)
th.WriteF("/app/https/sts-patch.yaml", patchService)
}

func writeConfigOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/config", configKustomization)
th.WriteF("/app/config/sts-patch.yaml", patchEnvFromConfig)
}

func writeTolerationsOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/tolerations", tolerationsKustomization)
th.WriteF("/app/tolerations/sts-patch.yaml", patchTolerations)
}

func writeStorageOverlay(th *kusttest_test.KustTestHarness) {
th.WriteK("/app/storage", storageKustomization)
th.WriteF("/app/storage/sts-patch.json", patchJsonPVCTemplate)
}

// Here's a complex kustomization scenario that combines multiple overlays
// on a common base:
//
// dev prod
// | |
// | |
// + ------- + + ------------ + ------------- +
// | | | | |
// | | | | |
// v | v v v
// storage + -----> config tolerations https
// | | | |
// | | | |
// | + --- + + --- + |
// | | | |
// | v v |
// + -----------------------> base <------------------ +
//
// The base resource is a statefulset. Each intermediate overlay manages or
// generates new resources and patches different aspects of the same base
// resource, without using any of the `namePrefix`, `nameSuffix` or `namespace`
// kustomization keywords.
//
// Intermediate overlays:
// - storage: Changes the storage class of the stateful set with a JSON patch.
// - config: Generates a config map and adds a field as an environment
// variable.
// - tolerations: Adds a new tolerations field in the spec.
// - https: Adds a new service resource and changes the service name in the
// stateful set.
//
// Top overlays:
// - dev: Combines the storage and config intermediate overlays.
// - prod: Combines the config, tolerations and https intermediate overlays.

func TestComplexComposition_Dev_Failure(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/dev")
writeStatefulSetBase(th)
writeStorageOverlay(th)
writeConfigOverlay(th)
writeTolerationsOverlay(th)
writeHTTPSOverlay(th)

th.WriteK("/app/dev", `
resources:
- ../storage
- ../config
`)

_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("Expected resource accumulation error")
}
if !strings.Contains(
err.Error(), "already registered id: apps_v1_StatefulSet|~X|my-sts") {
t.Fatalf("Unexpected err: %v", err)
}

// Expected Output
const devMergeResult = `
apiVersion: v1
data:
MY_ENV: foo
kind: ConfigMap
metadata:
name: my-config
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
serviceName: my-svc
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: app
image: my-image
envFrom:
- configMapRef:
name: my-config
volumeClaimTemplates:
- spec:
storageClassName: my-sc
`
}

func TestComplexComposition_Prod_Failure(t *testing.T) {
th := kusttest_test.NewKustTestHarness(t, "/app/prod")
writeStatefulSetBase(th)
writeStorageOverlay(th)
writeConfigOverlay(th)
writeTolerationsOverlay(th)
writeHTTPSOverlay(th)

th.WriteK("/app/prod", `
resources:
- ../config
- ../tolerations
- ../https
`)

_, err := th.MakeKustTarget().MakeCustomizedResMap()
if err == nil {
t.Fatalf("Expected resource accumulation error")
}
if !strings.Contains(
err.Error(), "already registered id: apps_v1_StatefulSet|~X|my-sts") {
t.Fatalf("Unexpected err: %v", err)
}

// Expected Output
const prodMergeResult = `
apiVersion: v1
data:
MY_ENV: foo
kind: ConfigMap
metadata:
name: my-config
---
apiVersion: v1
kind: Service
metadata:
name: my-https-svc
spec:
ports:
- name: https
port: 443
protocol: TCP
selector:
app: my-app
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-sts
spec:
serviceName: my-https-svc
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- image: my-image
envFrom:
- configMapRef:
name: my-config
name: app
tolerations:
- effect: NoExecute
key: node.kubernetes.io/not-ready
tolerationSeconds: 30
volumeClaimTemplates:
- spec:
storageClassName: default
`
}