From e87c2a5fad724c6c0e1ae864abf4c2733fa0d505 Mon Sep 17 00:00:00 2001 From: Bartosz Majsak Date: Wed, 13 Mar 2024 07:34:49 +0100 Subject: [PATCH] feat(tmpl): fails when key does not exist (#916) The templates used in Feature SDK are not intended (at least right now) to provide conditional rendering like in Helm. Thus we should fail fast if the Feature's underlying map does not provide the key referred to in a template. This is achieved by passing the parsing option (missingkey=error) to built-in Golang templating. > [!NOTE] > This works out of the box with `struct`s but we should also fail when dealing with `map`s. --- pkg/feature/manifest.go | 5 ++++- pkg/feature/manifest_test.go | 21 +++++++++++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/pkg/feature/manifest.go b/pkg/feature/manifest.go index f5af0a4eb6a..1793c56bbdc 100644 --- a/pkg/feature/manifest.go +++ b/pkg/feature/manifest.go @@ -88,7 +88,10 @@ func (t *templateManifest) Process(data any) ([]*unstructured.Unstructured, erro return nil, fmt.Errorf("failed to create file: %w", err) } - tmpl, err := template.New(t.name).Funcs(template.FuncMap{"ReplaceChar": ReplaceChar}).Parse(string(content)) + tmpl, err := template.New(t.name). + Option("missingkey=error"). + Funcs(template.FuncMap{"ReplaceChar": ReplaceChar}). + Parse(string(content)) if err != nil { return nil, fmt.Errorf("failed to parse template: %w", err) } diff --git a/pkg/feature/manifest_test.go b/pkg/feature/manifest_test.go index 01dafb8c20f..f66d75eb7d0 100644 --- a/pkg/feature/manifest_test.go +++ b/pkg/feature/manifest_test.go @@ -75,8 +75,7 @@ data: }) Describe("Templated Manifest Processing", func() { - BeforeEach(func() { - resourceYaml := ` + resourceYaml := ` apiVersion: v1 kind: ConfigMap metadata: @@ -85,11 +84,29 @@ metadata: data: key: Data ` + + BeforeEach(func() { path = "path/to/template.yaml" err := afero.WriteFile(inMemFS.Afs, path, []byte(resourceYaml), 0644) Expect(err).ToNot(HaveOccurred()) }) + It("should fail when template refers to non existing key", func() { + // given + pathToBrokenTpl := filepath.Join("broken", path) + Expect(afero.WriteFile(inMemFS.Afs, pathToBrokenTpl, []byte(resourceYaml+"\n {{ .NotExistingKey }}"), 0644)).To(Succeed()) + data := map[string]string{ + "TargetNamespace": "template-ns", + } + manifest := feature.CreateTemplateManifestFrom(inMemFS, pathToBrokenTpl) + + // when + _, err := manifest.Process(data) + + // then + Expect(err).Should(MatchError(ContainSubstring("at <.NotExistingKey>: map has no entry for key"))) + }) + It("should substitute target namespace in the templated manifest", func() { // given data := feature.Spec{