diff --git a/pkg/kusttest/kusttestharness.go b/pkg/kusttest/kusttestharness.go index d0405e077..2e5adf943 100644 --- a/pkg/kusttest/kusttestharness.go +++ b/pkg/kusttest/kusttestharness.go @@ -31,19 +31,18 @@ type KustTestHarness struct { } func NewKustTestHarness(t *testing.T, path string) *KustTestHarness { - return newHarness( - t, path, plugins.DefaultPluginConfig()) + return NewKustTestHarnessFull( + t, path, loader.RestrictionRootOnly, plugins.DefaultPluginConfig()) } func NewKustTestPluginHarness(t *testing.T, path string) *KustTestHarness { - return newHarness( - t, path, plugins.ActivePluginConfig()) + return NewKustTestHarnessFull( + t, path, loader.RestrictionRootOnly, plugins.ActivePluginConfig()) } -func newHarness( - t *testing.T, path string, - pc *types.PluginConfig) *KustTestHarness { - return NewKustTestHarnessFull(t, path, loader.RestrictionRootOnly, pc) +func NewKustTestNoLoadRestrictorHarness(t *testing.T, path string) *KustTestHarness { + return NewKustTestHarnessFull( + t, path, loader.RestrictionNone, plugins.DefaultPluginConfig()) } func NewKustTestHarnessFull( diff --git a/pkg/target/diamondcomposition_test.go b/pkg/target/diamondcomposition_test.go index c30a1b329..137f2e21c 100644 --- a/pkg/target/diamondcomposition_test.go +++ b/pkg/target/diamondcomposition_test.go @@ -4,10 +4,13 @@ package target_test import ( + "fmt" + "path/filepath" "strings" "testing" - kusttest_test "sigs.k8s.io/kustomize/v3/pkg/kusttest" + "sigs.k8s.io/kustomize/v3/pkg/kusttest" + "sigs.k8s.io/kustomize/v3/pkg/plugins" ) const patchAddProbe = ` @@ -26,6 +29,11 @@ spec: port: 8080 ` +const container = `{ "image": "my-image", "livenessProbe": { "httpGet" : {"path": "/healthz", "port": 8080 } }, "name": "my-deployment"}` + +const patchJsonAddProbe = `[{"op": "replace", "path": "/spec/template/spec/containers/0", "value": ` + + container + `}]` + const patchDnsPolicy = ` apiVersion: apps/v1 kind: Deployment @@ -36,6 +44,7 @@ spec: spec: dnsPolicy: ClusterFirst ` +const patchJsonDnsPolicy = `[{"op": "add", "path": "/spec/template/spec/dnsPolicy", "value": "ClusterFirst"}]` const patchRestartPolicy = ` apiVersion: apps/v1 @@ -47,21 +56,9 @@ spec: spec: restartPolicy: Always ` +const patchJsonRestartPolicy = `[{"op": "add", "path": "/spec/template/spec/restartPolicy", "value": "Always"}]` -// Here's a composite kustomization, that combines multiple overlays -// (probes, dns and restart policies) which patch the same base resource. -// -// The base resource is a deployment and the overlays patch aspects -// of it, without using any of the `namePrefix`, `nameSuffix` or `namespace` -// kustomization keywords. -// -// composite -// / | \ -// probe dns restart -// \ | / -// base -// -func writeDiamondCompositionBase(th *kusttest_test.KustTestHarness) { +func writeDeploymentBase(th *kusttest_test.KustTestHarness) { th.WriteK("/app/base", ` resources: - deployment.yaml @@ -112,9 +109,22 @@ patchesStrategicMerge: th.WriteF("/app/restart/dep-patch.yaml", patchRestartPolicy) } -func TestCompositeDiamond(t *testing.T) { +// Here's a composite kustomization, that combines multiple overlays +// (replicas, dns and metadata) which patch the same base resource. +// +// The base resource is a deployment and the overlays patch aspects +// of it, without using any of the `namePrefix`, `nameSuffix` or `namespace` +// kustomization keywords. +// +// composite +// / | \ +// probe dns restart +// \ | / +// base +// +func TestIssue1251_CompositeDiamond_Failure(t *testing.T) { th := kusttest_test.NewKustTestHarness(t, "/app/composite") - writeDiamondCompositionBase(th) + writeDeploymentBase(th) writeProbeOverlay(th) writeDNSOverlay(th) writeRestartOverlay(th) @@ -155,11 +165,11 @@ spec: restartPolicy: Always ` -// This test reuses some methods from TestCompositeDiamond, +// This test reuses some methods from TestIssue1251_CompositeDiamond, // but overwrites the kustomization files in the overlays. -func TestStackedOverlays(t *testing.T) { +func TestIssue1251_Patches_Overlayed(t *testing.T) { th := kusttest_test.NewKustTestHarness(t, "/app/restart") - writeDiamondCompositionBase(th) + writeDeploymentBase(th) // probe overlays base. writeProbeOverlay(th) @@ -189,9 +199,9 @@ patchesStrategicMerge: th.AssertActualEqualsExpected(m, expectedPatchedDeployment) } -func TestMultiPatch(t *testing.T) { +func TestIssue1251_Patches_Local(t *testing.T) { th := kusttest_test.NewKustTestHarness(t, "/app/composite") - writeDiamondCompositionBase(th) + writeDeploymentBase(th) th.WriteK("/app/composite", ` resources: @@ -211,3 +221,271 @@ patchesStrategicMerge: } th.AssertActualEqualsExpected(m, expectedPatchedDeployment) } + +func definePatchDirStructure(th *kusttest_test.KustTestHarness) { + writeDeploymentBase(th) + + th.WriteF("/app/patches/patchRestartPolicy.yaml", patchRestartPolicy) + th.WriteF("/app/patches/patchDnsPolicy.yaml", patchDnsPolicy) + th.WriteF("/app/patches/patchAddProbe.yaml", patchAddProbe) +} + +// Fails due to file load restrictor. +func TestIssue1251_Patches_ProdVsDev_Failure(t *testing.T) { + th := kusttest_test.NewKustTestPluginHarness(t, "/app/prod") + definePatchDirStructure(th) + + th.WriteK("/app/prod", ` +resources: +- ../base +patchesStrategicMerge: +- ../patches/patchAddProbe.yaml +- ../patches/patchDnsPolicy.yaml +`) + + _, err := th.MakeKustTarget().MakeCustomizedResMap() + if err == nil { + t.Fatalf("expected error") + } + if !strings.Contains( + err.Error(), + "security; file '/app/patches/patchAddProbe.yaml' is not in or below '/app/prod'") { + t.Fatalf("unexpected error: %v", err) + } +} + +const prodDevMergeResult1 = ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-deployment +spec: + template: + spec: + containers: + - image: my-image + livenessProbe: + httpGet: + path: /healthz + port: 8080 + name: my-deployment + dnsPolicy: ClusterFirst +` + +const prodDevMergeResult2 = ` +apiVersion: apps/v1 +kind: Deployment +metadata: + name: my-deployment +spec: + template: + spec: + containers: + - image: my-image + name: my-deployment + dnsPolicy: ClusterFirst + restartPolicy: Always +` + +// This test does what +// TestIssue1251_Patches_ProdVsDev_Failure +// failed to do, because this test does the equivalent +// os specifying `--load_restrictor none` on the build. +// +// This allows the use patch files located outside the +// kustomization root, and not in a kustomization +// themselves. +// +// Doing so means the kustomization using them is no +// longer relocatable, not addressible via a git URL, +// and not git clonable. It's no longer self-contained. +// +// Likewise suppressing load restrictions happens for +// the entire build (i.e. everything can reach outside +// the kustomization root), opening the user to whatever +// threat the load restrictor was meant to address. +func TestIssue1251_Patches_ProdVsDev(t *testing.T) { + th := kusttest_test.NewKustTestNoLoadRestrictorHarness(t, "/app/prod") + definePatchDirStructure(th) + + th.WriteK("/app/prod", ` +resources: +- ../base +patchesStrategicMerge: +- ../patches/patchAddProbe.yaml +- ../patches/patchDnsPolicy.yaml +`) + m, err := th.MakeKustTarget().MakeCustomizedResMap() + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + th.AssertActualEqualsExpected(m, prodDevMergeResult1) + + th = kusttest_test.NewKustTestNoLoadRestrictorHarness(t, "/app/dev") + definePatchDirStructure(th) + + th.WriteK("/app/dev", ` +resources: +- ../base +patchesStrategicMerge: +- ../patches/patchDnsPolicy.yaml +- ../patches/patchRestartPolicy.yaml +`) + + m, err = th.MakeKustTarget().MakeCustomizedResMap() + if err != nil { + t.Fatalf("Err: %v", err) + } + th.AssertActualEqualsExpected(m, prodDevMergeResult2) +} + +func TestIssue1251_Plugins_ProdVsDev(t *testing.T) { + tc := plugins.NewEnvForTest(t).Set() + defer tc.Reset() + + tc.BuildGoPlugin( + "builtin", "", "PatchJson6902Transformer") + + th := kusttest_test.NewKustTestPluginHarness(t, "/app/prod") + defineTransformerDirStructure(th) + th.WriteK("/app/prod", ` +resources: +- ../base +transformers: +- ../patches/addProbe +- ../patches/addDnsPolicy +`) + + m, err := th.MakeKustTarget().MakeCustomizedResMap() + if err != nil { + t.Fatalf("Err: %v", err) + } + th.AssertActualEqualsExpected(m, prodDevMergeResult1) + + th = kusttest_test.NewKustTestPluginHarness(t, "/app/dev") + defineTransformerDirStructure(th) + th.WriteK("/app/dev", ` +resources: +- ../base +transformers: +- ../patches/addRestartPolicy +- ../patches/addDnsPolicy +`) + + m, err = th.MakeKustTarget().MakeCustomizedResMap() + if err != nil { + t.Fatalf("Err: %v", err) + } + th.AssertActualEqualsExpected(m, prodDevMergeResult2) +} + +func TestIssue1251_Plugins_Local(t *testing.T) { + tc := plugins.NewEnvForTest(t).Set() + defer tc.Reset() + + tc.BuildGoPlugin( + "builtin", "", "PatchJson6902Transformer") + + th := kusttest_test.NewKustTestPluginHarness(t, "/app/composite") + writeDeploymentBase(th) + + writeJsonTransformerPluginConfig( + th, "/app/composite", "addDnsPolicy", patchJsonDnsPolicy) + writeJsonTransformerPluginConfig( + th, "/app/composite", "addRestartPolicy", patchJsonRestartPolicy) + writeJsonTransformerPluginConfig( + th, "/app/composite", "addProbe", patchJsonAddProbe) + + th.WriteK("/app/composite", ` +resources: +- ../base +transformers: +- addDnsPolicyConfig.yaml +- addRestartPolicyConfig.yaml +- addProbeConfig.yaml +`) + m, err := th.MakeKustTarget().MakeCustomizedResMap() + if err != nil { + t.Fatalf("Err: %v", err) + } + th.AssertActualEqualsExpected(m, expectedPatchedDeployment) +} + +func writeJsonTransformerPluginConfig( + th *kusttest_test.KustTestHarness, path, name, patch string) { + th.WriteF(filepath.Join(path, name+"Config.yaml"), + fmt.Sprintf(` +apiVersion: builtin +kind: PatchJson6902Transformer +metadata: + name: %s +target: + group: apps + version: v1 + kind: Deployment + name: my-deployment +jsonOp: '%s' +`, name, patch)) +} + +// Remote in the sense that they are bundled in a different kustomization. +func TestIssue1251_Plugins_Bundled(t *testing.T) { + tc := plugins.NewEnvForTest(t).Set() + defer tc.Reset() + + tc.BuildGoPlugin( + "builtin", "", "PatchJson6902Transformer") + + th := kusttest_test.NewKustTestPluginHarness(t, "/app/composite") + writeDeploymentBase(th) + + th.WriteK("/app/patches", ` +resources: +- addDnsPolicyConfig.yaml +- addRestartPolicyConfig.yaml +- addProbeConfig.yaml +`) + writeJsonTransformerPluginConfig( + th, "/app/patches", "addDnsPolicy", patchJsonDnsPolicy) + writeJsonTransformerPluginConfig( + th, "/app/patches", "addRestartPolicy", patchJsonRestartPolicy) + writeJsonTransformerPluginConfig( + th, "/app/patches", "addProbe", patchJsonAddProbe) + + th.WriteK("/app/composite", ` +resources: +- ../base +transformers: +- ../patches +`) + m, err := th.MakeKustTarget().MakeCustomizedResMap() + if err != nil { + t.Fatalf("Err: %v", err) + } + th.AssertActualEqualsExpected(m, expectedPatchedDeployment) +} + +func defineTransformerDirStructure(th *kusttest_test.KustTestHarness) { + writeDeploymentBase(th) + + th.WriteK("/app/patches/addDnsPolicy", ` +resources: +- addDnsPolicyConfig.yaml +`) + writeJsonTransformerPluginConfig( + th, "/app/patches/addDnsPolicy", "addDnsPolicy", patchJsonDnsPolicy) + + th.WriteK("/app/patches/addRestartPolicy", ` +resources: +- addRestartPolicyConfig.yaml +`) + writeJsonTransformerPluginConfig( + th, "/app/patches/addRestartPolicy", "addRestartPolicy", patchJsonRestartPolicy) + + th.WriteK("/app/patches/addProbe", ` +resources: +- addProbeConfig.yaml +`) + writeJsonTransformerPluginConfig( + th, "/app/patches/addProbe", "addProbe", patchJsonAddProbe) +}