Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
7 changes: 4 additions & 3 deletions api/internal/builtins/NamespaceTransformer.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ Advanced Usage
* [last mile helm](chart.md) - Make last mile modifications to
a helm chart.

* [helm namespace inheritance](helmNamespace/README.md) - Verify that an overlay namespace fills unset namespaces in Helm output without overwriting explicit chart namespaces.

* [secret generation](secretGeneratorPlugin.md) - Generating secrets from a plugin.

* [remote sources](goGetterGeneratorPlugin.md) - Generating from remote sources.
Expand Down
53 changes: 53 additions & 0 deletions examples/helmNamespace/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Helm Namespace Example

This example exercises namespace transformation on resources generated from a local Helm chart.

The example kustomization sets a namespace for Helm-generated resources that do not already declare one, while preserving any namespace explicitly emitted by the chart.

## Build the example

This example defines the `helm` command as:

<!-- @defineHelmCommand @testHelm -->
```sh
helmCommand=${MYGOBIN:-~/go/bin}/helmV3
```

Use the checked-in example:

<!-- @defineExampleHome @testHelm -->
```sh
EXAMPLE_HOME=examples/helmNamespace
```

Build the example with Helm enabled:

<!-- @buildOverlay @testHelm -->
```sh
output=$(kustomize build \
--enable-helm \
--helm-command "$helmCommand" \
"$EXAMPLE_HOME")
printf '%s\n' "$output"
```

The Service is emitted by the chart without a namespace, so the example namespace should be applied:

<!-- @checkMissingNamespaceFilled @testHelm -->
```sh
printf '%s\n' "$output" | grep -A4 'name: chart-service' | grep 'namespace: top-level-ns'
Comment thread
Skaronator marked this conversation as resolved.
Outdated
```

The ConfigMap is emitted by the chart with an explicit namespace, so that value should be preserved:

<!-- @checkExistingNamespacePreserved @testHelm -->
```sh
printf '%s\n' "$output" | grep -A4 'name: chart-config' | grep 'namespace: chart-owned-ns'
```

The Secret is emitted by the chart with an release namespace, so that value should be preserved:

<!-- @checkExistingNamespacePreserved @testHelm -->
```sh
printf '%s\n' "$output" | grep -A4 'name: chart-secret' | grep 'namespace: chart-ns'
```
4 changes: 4 additions & 0 deletions examples/helmNamespace/charts/namespace-fill/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v2
name: namespace-fill
version: 0.1.0
type: application
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: chart-config
namespace: chart-owned-ns
data:
owner: helm-chart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: chart-secret
namespace: {{ .Release.Namespace }}
data:
.secret-file: dmFsdWUtMg0KDQo=
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: v1
kind: Service
metadata:
name: chart-service
spec:
selector:
app: chart-service
ports:
- port: 80
targetPort: 8080
Empty file.
11 changes: 11 additions & 0 deletions examples/helmNamespace/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: top-level-ns

helmGlobals:
chartHome: charts

helmCharts:
- name: namespace-fill
namespace: chart-ns
1 change: 1 addition & 0 deletions hack/testExamplesAgainstKustomize.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ if onLinuxAndNotOnRemoteCI; then
echo "On linux, and not on remote CI. Running helm tests."
make $MYGOBIN/helmV3
mdrip --mode test --label testHelm examples/chart.md
mdrip --mode test --label testHelm examples/helmNamespace/README.md
else
echo "Skipping helm tests against $version."
echo "Helm chart inflator has new features (includeCRD) only in HEAD."
Expand Down
7 changes: 4 additions & 3 deletions plugin/builtin/namespacetransformer/NamespaceTransformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,16 +57,17 @@ func (p *plugin) Transform(m resmap.ResMap) error {
// Don't mutate empty objects?
continue
}
helmGenerated := false
if annotations := r.GetAnnotations(konfig.HelmGeneratedAnnotation); annotations[konfig.HelmGeneratedAnnotation] == "true" {
// Don't apply namespace on Helm generated manifest. Helm should take care of it.
continue
// Preserve namespaces emitted by Helm, but still fill any missing namespace fields.
helmGenerated = true
}
r.StorePreviousId()
if err := r.ApplyFilter(namespace.Filter{
Namespace: p.Namespace,
FsSlice: p.FieldSpecs,
SetRoleBindingSubjects: p.SetRoleBindingSubjects,
UnsetOnly: p.UnsetOnly,
UnsetOnly: p.UnsetOnly || helmGenerated,
}); err != nil {
return err
}
Expand Down
38 changes: 37 additions & 1 deletion plugin/builtin/namespacetransformer/NamespaceTransformer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@ subjects:
})
}

func TestNamespaceTransformer_SkipHelmOrigin(t *testing.T) {
func TestNamespaceTransformer_HelmOriginPreservesExistingNamespace(t *testing.T) {
th := kusttest_test.MakeEnhancedHarness(t).
PrepBuiltin("NamespaceTransformer")
defer th.Reset()
Expand Down Expand Up @@ -804,3 +804,39 @@ metadata:
namespace: helm-ns
`)
}

func TestNamespaceTransformer_HelmOriginSetsMissingNamespace(t *testing.T) {
th := kusttest_test.MakeEnhancedHarness(t).
PrepBuiltin("NamespaceTransformer")
defer th.Reset()

rmF := resmap.NewFactory(provider.NewDefaultDepProvider().GetResourceFactory())
rm, err := rmF.NewResMapFromBytes([]byte(`apiVersion: v1
kind: Service
metadata:
name: svc
annotations:
this-should-be-keept: "true"
`))
require.NoError(t, err)
r := rm.Resources()[0]
require.NoError(t, r.RNode.PipeE(kyaml.SetAnnotation(konfig.HelmGeneratedAnnotation, "true")))

rm, err = th.RunTransformerFromResMap(`
apiVersion: builtin
kind: NamespaceTransformer
metadata:
name: notImportantHere
namespace: test
`+defaultFieldSpecs, rm)
require.NoError(t, err)
require.NoError(t, rm.RemoveOriginAnnotations())
th.AssertActualEqualsExpectedNoIdAnnotations(rm, `apiVersion: v1
kind: Service
metadata:
annotations:
this-should-be-keept: "true"
name: svc
namespace: test
`)
}