mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
This PR intends to move the loader api to internal. Only the necessary methods which are needed for the api have been put into `pkg/loader.go`. Signed-off-by: Varsha Prasad Narsing <varshaprasad96@gmail.com>
770 lines
14 KiB
Go
770 lines
14 KiB
Go
// Copyright 2020 The Kubernetes Authors.
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package krusty_test
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"testing"
|
|
|
|
"sigs.k8s.io/kustomize/api/internal/loader"
|
|
"sigs.k8s.io/kustomize/api/konfig"
|
|
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
|
)
|
|
|
|
type FileGen func(kusttest_test.Harness)
|
|
|
|
func writeC(path string, content string) FileGen {
|
|
return func(th kusttest_test.Harness) {
|
|
th.WriteC(path, content)
|
|
}
|
|
}
|
|
|
|
func writeF(path string, content string) FileGen {
|
|
return func(th kusttest_test.Harness) {
|
|
th.WriteF(path, content)
|
|
}
|
|
}
|
|
|
|
func writeK(path string, content string) FileGen {
|
|
return func(th kusttest_test.Harness) {
|
|
th.WriteK(path, content)
|
|
}
|
|
}
|
|
|
|
func writeTestBase(th kusttest_test.Harness) {
|
|
th.WriteK("base", `
|
|
resources:
|
|
- deploy.yaml
|
|
configMapGenerator:
|
|
- name: my-configmap
|
|
literals:
|
|
- testValue=purple
|
|
- otherValue=green
|
|
`)
|
|
th.WriteF("base/deploy.yaml", `
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: storefront
|
|
spec:
|
|
replicas: 1
|
|
`)
|
|
}
|
|
|
|
func writeTestComponent(th kusttest_test.Harness) {
|
|
th.WriteC("comp", `
|
|
namePrefix: comp-
|
|
replicas:
|
|
- name: storefront
|
|
count: 3
|
|
resources:
|
|
- stub.yaml
|
|
configMapGenerator:
|
|
- name: my-configmap
|
|
behavior: merge
|
|
literals:
|
|
- testValue=blue
|
|
- compValue=red
|
|
`)
|
|
th.WriteF("comp/stub.yaml", `
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: stub
|
|
spec:
|
|
replicas: 1
|
|
`)
|
|
}
|
|
|
|
func writeOverlayProd(th kusttest_test.Harness) {
|
|
th.WriteK("prod", `
|
|
resources:
|
|
- ../base
|
|
- db
|
|
|
|
components:
|
|
- ../comp
|
|
`)
|
|
writeDB(th)
|
|
}
|
|
|
|
func writeDB(th kusttest_test.Harness) {
|
|
deployment("db", "prod/db")(th)
|
|
}
|
|
|
|
func deployment(name string, path string) FileGen {
|
|
return writeF(path, fmt.Sprintf(`
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: %s
|
|
spec:
|
|
type: Logical
|
|
`, name))
|
|
}
|
|
|
|
func TestComponent(t *testing.T) {
|
|
testCases := map[string]struct {
|
|
input []FileGen
|
|
runPath string
|
|
expectedOutput string
|
|
}{
|
|
// Components are inserted into the resource hierarchy as the parent of those
|
|
// resources that come before it in the resources list of the parent Kustomization.
|
|
"basic-component": {
|
|
input: []FileGen{writeTestBase, writeTestComponent, writeOverlayProd},
|
|
runPath: "prod",
|
|
expectedOutput: `
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: comp-storefront
|
|
spec:
|
|
replicas: 3
|
|
---
|
|
apiVersion: v1
|
|
data:
|
|
compValue: red
|
|
otherValue: green
|
|
testValue: blue
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: comp-my-configmap-97647ckcmg
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: comp-db
|
|
spec:
|
|
type: Logical
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: comp-stub
|
|
spec:
|
|
replicas: 1
|
|
`,
|
|
},
|
|
"multiple-components": {
|
|
input: []FileGen{writeTestBase, writeTestComponent, writeDB,
|
|
writeC("additionalcomp", `
|
|
configMapGenerator:
|
|
- name: my-configmap
|
|
behavior: merge
|
|
literals:
|
|
- otherValue=orange
|
|
`),
|
|
writeK("prod", `
|
|
resources:
|
|
- ../base
|
|
- db
|
|
|
|
components:
|
|
- ../comp
|
|
- ../additionalcomp
|
|
`),
|
|
},
|
|
runPath: "prod",
|
|
expectedOutput: `
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: comp-storefront
|
|
spec:
|
|
replicas: 3
|
|
---
|
|
apiVersion: v1
|
|
data:
|
|
compValue: red
|
|
otherValue: orange
|
|
testValue: blue
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: comp-my-configmap-g486mb229k
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: comp-db
|
|
spec:
|
|
type: Logical
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: comp-stub
|
|
spec:
|
|
replicas: 1
|
|
`,
|
|
},
|
|
"nested-components": {
|
|
input: []FileGen{writeTestBase, writeTestComponent, writeDB,
|
|
writeC("additionalcomp", `
|
|
components:
|
|
- ../comp
|
|
configMapGenerator:
|
|
- name: my-configmap
|
|
behavior: merge
|
|
literals:
|
|
- otherValue=orange
|
|
`),
|
|
writeK("prod", `
|
|
resources:
|
|
- ../base
|
|
- db
|
|
|
|
components:
|
|
- ../additionalcomp
|
|
`),
|
|
},
|
|
runPath: "prod",
|
|
expectedOutput: `
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: comp-storefront
|
|
spec:
|
|
replicas: 3
|
|
---
|
|
apiVersion: v1
|
|
data:
|
|
compValue: red
|
|
otherValue: orange
|
|
testValue: blue
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: comp-my-configmap-g486mb229k
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: comp-db
|
|
spec:
|
|
type: Logical
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: comp-stub
|
|
spec:
|
|
replicas: 1
|
|
`,
|
|
},
|
|
// If a component sets a name prefix on a base, then that base can also be separately included
|
|
// without being affected by the component in another branch of the resource tree
|
|
"basic-component-with-repeated-base": {
|
|
input: []FileGen{writeTestBase, writeTestComponent, writeOverlayProd,
|
|
writeK("repeated", `
|
|
resources:
|
|
- ../base
|
|
- ../prod
|
|
`),
|
|
},
|
|
runPath: "repeated",
|
|
expectedOutput: `
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: storefront
|
|
spec:
|
|
replicas: 1
|
|
---
|
|
apiVersion: v1
|
|
data:
|
|
otherValue: green
|
|
testValue: purple
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: my-configmap-9cd648hm8f
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: comp-storefront
|
|
spec:
|
|
replicas: 3
|
|
---
|
|
apiVersion: v1
|
|
data:
|
|
compValue: red
|
|
otherValue: green
|
|
testValue: blue
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: comp-my-configmap-97647ckcmg
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: comp-db
|
|
spec:
|
|
type: Logical
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: comp-stub
|
|
spec:
|
|
replicas: 1
|
|
`,
|
|
},
|
|
"applying-component-directly-should-be-same-as-kustomization": {
|
|
input: []FileGen{writeTestBase, writeTestComponent,
|
|
writeC("direct-component", `
|
|
resources:
|
|
- ../base
|
|
configMapGenerator:
|
|
- name: my-configmap
|
|
behavior: merge
|
|
literals:
|
|
- compValue=red
|
|
- testValue=blue
|
|
`),
|
|
},
|
|
runPath: "direct-component",
|
|
expectedOutput: `
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: storefront
|
|
spec:
|
|
replicas: 1
|
|
---
|
|
apiVersion: v1
|
|
data:
|
|
compValue: red
|
|
otherValue: green
|
|
testValue: blue
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: my-configmap-97647ckcmg
|
|
`,
|
|
},
|
|
"missing-optional-component-api-version": {
|
|
input: []FileGen{writeTestBase, writeOverlayProd,
|
|
writeF("comp/"+konfig.DefaultKustomizationFileName(), `
|
|
kind: Component
|
|
configMapGenerator:
|
|
- name: my-configmap
|
|
behavior: merge
|
|
literals:
|
|
- otherValue=orange
|
|
`),
|
|
},
|
|
runPath: "prod",
|
|
expectedOutput: `
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: storefront
|
|
spec:
|
|
replicas: 1
|
|
---
|
|
apiVersion: v1
|
|
data:
|
|
otherValue: orange
|
|
testValue: purple
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: my-configmap-6hhdg8gkdg
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: db
|
|
spec:
|
|
type: Logical
|
|
`,
|
|
},
|
|
// See how nameSuffix "-b" is also added to the resources included by "comp-a" because they are in the
|
|
// accumulator when "comp-b" is accumulated. In practice we could use simple Kustomizations for this example.
|
|
"components-can-add-the-same-base-if-the-first-renames-resources": {
|
|
input: []FileGen{writeTestBase,
|
|
deployment("proxy", "comp-a/proxy.yaml"),
|
|
writeC("comp-a", `
|
|
resources:
|
|
- ../base
|
|
|
|
nameSuffix: "-a"
|
|
`),
|
|
writeC("comp-b", `
|
|
resources:
|
|
- ../base
|
|
|
|
nameSuffix: "-b"
|
|
`),
|
|
writeK("prod", `
|
|
components:
|
|
- ../comp-a
|
|
- ../comp-b`),
|
|
},
|
|
runPath: "prod",
|
|
expectedOutput: `
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: storefront-a-b
|
|
spec:
|
|
replicas: 1
|
|
---
|
|
apiVersion: v1
|
|
data:
|
|
otherValue: green
|
|
testValue: purple
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: my-configmap-a-b-9cd648hm8f
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: storefront-b
|
|
spec:
|
|
replicas: 1
|
|
---
|
|
apiVersion: v1
|
|
data:
|
|
otherValue: green
|
|
testValue: purple
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: my-configmap-b-9cd648hm8f
|
|
`,
|
|
},
|
|
|
|
"multiple-bases-can-add-the-same-component-if-it-doesn-not-define-named-entities": {
|
|
input: []FileGen{
|
|
writeC("comp", `
|
|
namespace: prod
|
|
`),
|
|
writeK("base-a", `
|
|
resources:
|
|
- proxy.yaml
|
|
|
|
components:
|
|
- ../comp
|
|
`),
|
|
deployment("proxy-a", "base-a/proxy.yaml"),
|
|
writeK("base-b", `
|
|
resources:
|
|
- proxy.yaml
|
|
|
|
components:
|
|
- ../comp
|
|
`),
|
|
deployment("proxy-b", "base-b/proxy.yaml"),
|
|
writeK("prod", `
|
|
resources:
|
|
- proxy.yaml
|
|
- ../base-a
|
|
- ../base-b
|
|
`),
|
|
deployment("proxy-prod", "prod/proxy.yaml"),
|
|
},
|
|
runPath: "prod",
|
|
// Note that the namepsace has not been applied to proxy-prod because it was not in scope when the
|
|
// component was applied
|
|
expectedOutput: `
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: proxy-prod
|
|
spec:
|
|
type: Logical
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: proxy-a
|
|
namespace: prod
|
|
spec:
|
|
type: Logical
|
|
---
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: proxy-b
|
|
namespace: prod
|
|
spec:
|
|
type: Logical
|
|
`,
|
|
},
|
|
}
|
|
|
|
for tn, tc := range testCases {
|
|
t.Run(tn, func(t *testing.T) {
|
|
th := kusttest_test.MakeHarness(t)
|
|
for _, f := range tc.input {
|
|
f(th)
|
|
}
|
|
m := th.Run(tc.runPath, th.MakeDefaultOptions())
|
|
th.AssertActualEqualsExpected(m, tc.expectedOutput)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestComponentErrors(t *testing.T) {
|
|
testCases := map[string]struct {
|
|
input []FileGen
|
|
runPath string
|
|
expectedError string
|
|
}{
|
|
"components-cannot-be-added-to-resources": {
|
|
input: []FileGen{writeTestBase, writeTestComponent,
|
|
writeK("compinres", `
|
|
resources:
|
|
- ../base
|
|
- ../comp
|
|
`),
|
|
},
|
|
runPath: "compinres",
|
|
expectedError: "expected kind != 'Component' for path '/comp'",
|
|
},
|
|
"kustomizations-cannot-be-added-to-components": {
|
|
input: []FileGen{writeTestBase, writeTestComponent,
|
|
writeK("kustincomponents", `
|
|
components:
|
|
- ../base
|
|
- ../comp
|
|
`),
|
|
},
|
|
runPath: "kustincomponents",
|
|
expectedError: "accumulating components: accumulateDirectory: \"expected kind 'Component' for path " +
|
|
"'/base' but got 'Kustomization'",
|
|
},
|
|
"files-cannot-be-added-to-components-list": {
|
|
input: []FileGen{writeTestBase,
|
|
writeF("filesincomponents/stub.yaml", `
|
|
apiVersion: v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: stub
|
|
spec:
|
|
replicas: 1
|
|
`),
|
|
writeK("filesincomponents", `
|
|
components:
|
|
- stub.yaml
|
|
- ../comp
|
|
`),
|
|
},
|
|
runPath: "filesincomponents",
|
|
expectedError: fmt.Sprintf("%s: '%s'", loader.ErrRtNotDir.Error(), "/filesincomponents/stub.yaml"),
|
|
},
|
|
"invalid-component-api-version": {
|
|
input: []FileGen{writeTestBase, writeOverlayProd,
|
|
writeF("comp/"+konfig.DefaultKustomizationFileName(), `
|
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
|
kind: Component
|
|
configMapGenerator:
|
|
- name: my-configmap
|
|
behavior: merge
|
|
literals:
|
|
- otherValue=orange
|
|
`),
|
|
},
|
|
runPath: "prod",
|
|
expectedError: "apiVersion for Component should be kustomize.config.k8s.io/v1alpha1",
|
|
},
|
|
"components-cannot-add-the-same-resource": {
|
|
input: []FileGen{writeTestBase,
|
|
writeC("comp-a", `
|
|
resources:
|
|
- proxy.yaml
|
|
`),
|
|
deployment("proxy", "comp-a/proxy.yaml"),
|
|
writeC("comp-b", `
|
|
resources:
|
|
- proxy.yaml
|
|
`),
|
|
deployment("proxy", "comp-b/proxy.yaml"),
|
|
writeK("prod", `
|
|
resources:
|
|
- ../base
|
|
|
|
components:
|
|
- ../comp-a
|
|
- ../comp-b`),
|
|
},
|
|
runPath: "prod",
|
|
expectedError: "may not add resource with an already registered id: Deployment.v1.[noGrp]/proxy.[noNs]",
|
|
},
|
|
"components-cannot-add-the-same-base": {
|
|
input: []FileGen{writeTestBase,
|
|
deployment("proxy", "comp-a/proxy.yaml"),
|
|
writeC("comp-a", `
|
|
resources:
|
|
- ../base
|
|
`),
|
|
writeC("comp-b", `
|
|
resources:
|
|
- ../base
|
|
`),
|
|
writeK("prod", `
|
|
components:
|
|
- ../comp-a
|
|
- ../comp-b`),
|
|
},
|
|
runPath: "prod",
|
|
expectedError: "may not add resource with an already registered id: Deployment.v1.[noGrp]/storefront.[noNs]",
|
|
},
|
|
"components-cannot-add-bases-containing-the-same-resource": {
|
|
input: []FileGen{writeTestBase,
|
|
writeC("comp-a", `
|
|
resources:
|
|
- ../base-a
|
|
`),
|
|
writeK("base-a", `
|
|
resources:
|
|
- proxy.yaml
|
|
`),
|
|
deployment("proxy", "base-a/proxy.yaml"),
|
|
writeC("comp-b", `
|
|
resources:
|
|
- ../base-b
|
|
`),
|
|
writeK("base-b", `
|
|
resources:
|
|
- proxy.yaml
|
|
`),
|
|
deployment("proxy", "base-b/proxy.yaml"),
|
|
writeK("prod", `
|
|
resources:
|
|
- ../base
|
|
|
|
components:
|
|
- ../comp-a
|
|
- ../comp-b`),
|
|
},
|
|
runPath: "prod",
|
|
expectedError: "may not add resource with an already registered id: Deployment.v1.[noGrp]/proxy.[noNs]",
|
|
},
|
|
}
|
|
|
|
for tn, tc := range testCases {
|
|
t.Run(tn, func(t *testing.T) {
|
|
th := kusttest_test.MakeHarness(t)
|
|
for _, f := range tc.input {
|
|
f(th)
|
|
}
|
|
err := th.RunWithErr(tc.runPath, th.MakeDefaultOptions())
|
|
if err == nil || !strings.Contains(err.Error(), tc.expectedError) {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestOrderOfAccumulatedComponent(t *testing.T) {
|
|
tests := map[string]struct {
|
|
input []FileGen
|
|
expectedOutput string
|
|
}{
|
|
"components_using_a_generated_resource_by_configMapGenerator": {
|
|
input: []FileGen{
|
|
writeK("", `
|
|
resources:
|
|
- resource.yaml
|
|
components:
|
|
- components
|
|
configMapGenerator:
|
|
- name: generated-resource
|
|
literals:
|
|
- key=value
|
|
options:
|
|
disableNameSuffixHash: true`),
|
|
writeF("resource.yaml", `
|
|
apiVersion: v1
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: config-from-resources
|
|
data:
|
|
foo: bar`),
|
|
writeC("/components", `
|
|
apiVersion: kustomize.config.k8s.io/v1alpha1
|
|
kind: Component
|
|
nameSuffix: -suffix
|
|
`),
|
|
},
|
|
expectedOutput: `
|
|
apiVersion: v1
|
|
data:
|
|
foo: bar
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: config-from-resources-suffix
|
|
---
|
|
apiVersion: v1
|
|
data:
|
|
key: value
|
|
kind: ConfigMap
|
|
metadata:
|
|
name: generated-resource-suffix
|
|
`},
|
|
"components_are_applied_before_replacements_transformer_applied": {
|
|
input: []FileGen{
|
|
writeK("", `
|
|
resources:
|
|
- resource.yaml
|
|
components:
|
|
- components
|
|
replacements:
|
|
- source:
|
|
kind: Pod
|
|
name: myapp-pod
|
|
fieldPath: metadata.namespace
|
|
targets:
|
|
- select:
|
|
kind: Pod
|
|
name: myapp-pod
|
|
fieldPaths:
|
|
- spec.containers.[name=myapp-container].env.[name=CURRENT_POD_NAMESPACE].value`),
|
|
writeF("resource.yaml", `
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: myapp-pod
|
|
namespace: dev-assa
|
|
spec:
|
|
containers:
|
|
- image: busybox
|
|
name: myapp-container
|
|
env:
|
|
- name: CURRENT_POD_NAMESPACE
|
|
value: "$(PLACEHOLDER)"`),
|
|
writeC("/components", `
|
|
apiVersion: kustomize.config.k8s.io/v1alpha1
|
|
kind: Component
|
|
namespace: kustomize-namespace`),
|
|
},
|
|
expectedOutput: `
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: myapp-pod
|
|
namespace: kustomize-namespace
|
|
spec:
|
|
containers:
|
|
- env:
|
|
- name: CURRENT_POD_NAMESPACE
|
|
value: kustomize-namespace
|
|
image: busybox
|
|
name: myapp-container
|
|
`},
|
|
}
|
|
|
|
for testName, test := range tests {
|
|
t.Run(testName, func(t *testing.T) {
|
|
th := kusttest_test.MakeHarness(t)
|
|
for _, f := range test.input {
|
|
f(th)
|
|
}
|
|
m := th.Run(".", th.MakeDefaultOptions())
|
|
th.AssertActualEqualsExpected(m, test.expectedOutput)
|
|
})
|
|
}
|
|
}
|