From 0a5260b05be345123a5bab58cf11827bcb80ef0e Mon Sep 17 00:00:00 2001 From: Ivan Kolodiazhnyi Date: Mon, 30 Dec 2024 21:21:38 +0200 Subject: [PATCH] Add support to render template from string Signed-off-by: Ivan Kolodiazhnyi --- pkg/render/render.go | 40 ++++++++++++++++++++++++--------------- pkg/render/render_test.go | 14 +++++++------- 2 files changed, 32 insertions(+), 22 deletions(-) diff --git a/pkg/render/render.go b/pkg/render/render.go index aa26b018b..f65bfd76f 100644 --- a/pkg/render/render.go +++ b/pkg/render/render.go @@ -64,7 +64,7 @@ func RenderDir(manifestDir string, d *RenderData) ([]*unstructured.Unstructured, return nil } - objs, err := RenderTemplate(path, d) + objs, err := RenderFileTemplate(path, d) if err != nil { return err } @@ -77,10 +77,14 @@ func RenderDir(manifestDir string, d *RenderData) ([]*unstructured.Unstructured, return out, nil } -// RenderTemplate reads, renders, and attempts to parse a yaml or +func RenderTemplate(template string, d *RenderData) (*bytes.Buffer, error) { + return renderTemplate(template, d) +} + +// RenderFileTemplate reads, renders, and attempts to parse a yaml or // json file representing one or more k8s api objects -func RenderTemplate(path string, d *RenderData) ([]*unstructured.Unstructured, error) { - rendered, err := renderTemplate(path, d) +func RenderFileTemplate(path string, d *RenderData) ([]*unstructured.Unstructured, error) { + rendered, err := renderFileTemplate(path, d) if err != nil { return nil, err } @@ -112,8 +116,9 @@ func RenderTemplate(path string, d *RenderData) ([]*unstructured.Unstructured, e return out, nil } -func renderTemplate(path string, d *RenderData) (*bytes.Buffer, error) { - tmpl := template.New(path).Option("missingkey=error") +func renderTemplate(rawTemplate string, d *RenderData) (*bytes.Buffer, error) { + + tmpl := template.New("template").Option("missingkey=error") if d.Funcs != nil { tmpl.Funcs(d.Funcs) } @@ -122,23 +127,28 @@ func renderTemplate(path string, d *RenderData) (*bytes.Buffer, error) { tmpl.Funcs(template.FuncMap{"getOr": getOr, "isSet": isSet}) tmpl.Funcs(sprig.TxtFuncMap()) - source, err := os.ReadFile(path) - if err != nil { - return nil, errors.Wrapf(err, "failed to read manifest %s", path) - } - - if _, err := tmpl.Parse(string(source)); err != nil { - return nil, errors.Wrapf(err, "failed to parse manifest %s as template", path) + if _, err := tmpl.Parse(rawTemplate); err != nil { + return nil, errors.Wrapf(err, "failed to parse manifest %s as template", rawTemplate) } rendered := bytes.Buffer{} if err := tmpl.Execute(&rendered, d.Data); err != nil { - return nil, errors.Wrapf(err, "failed to render manifest %s", path) + return nil, errors.Wrapf(err, "failed to render manifest %s", rawTemplate) } return &rendered, nil } +func renderFileTemplate(path string, d *RenderData) (*bytes.Buffer, error) { + + source, err := os.ReadFile(path) + if err != nil { + return nil, errors.Wrapf(err, "failed to read manifest %s", path) + } + + return renderTemplate(string(source[:]), d) +} + func formateDeviceList(devs []DeviceInfo) string { out := "" for _, dev := range devs { @@ -232,7 +242,7 @@ func filterTemplates(toFilter map[string]string, path string, d *RenderData) err } // Render the template file - renderedData, err := renderTemplate(path, d) + renderedData, err := renderFileTemplate(path, d) if err != nil { return err } diff --git a/pkg/render/render_test.go b/pkg/render/render_test.go index be4d0f0bd..8be41eee4 100644 --- a/pkg/render/render_test.go +++ b/pkg/render/render_test.go @@ -12,7 +12,7 @@ func TestRenderSimple(t *testing.T) { d := MakeRenderData() - o1, err := RenderTemplate("testdata/manifests/simple.yaml", &d) + o1, err := RenderFileTemplate("testdata/manifests/simple.yaml", &d) g.Expect(err).NotTo(HaveOccurred()) g.Expect(o1).To(HaveLen(1)) @@ -36,7 +36,7 @@ func TestRenderSimple(t *testing.T) { g.Expect(o1[0].MarshalJSON()).To(MatchJSON(expected)) // test that json parses the same - o2, err := RenderTemplate("testdata/manifests/simple.json", &d) + o2, err := RenderFileTemplate("testdata/manifests/simple.json", &d) g.Expect(err).NotTo(HaveOccurred()) g.Expect(o2).To(Equal(o1)) } @@ -47,7 +47,7 @@ func TestRenderMultiple(t *testing.T) { p := "testdata/manifests/multiple.yaml" d := MakeRenderData() - o, err := RenderTemplate(p, &d) + o, err := RenderFileTemplate(p, &d) g.Expect(err).NotTo(HaveOccurred()) g.Expect(o).To(HaveLen(3)) @@ -64,19 +64,19 @@ func TestTemplate(t *testing.T) { // Test that missing variables are detected d := MakeRenderData() - _, err := RenderTemplate(p, &d) + _, err := RenderFileTemplate(p, &d) g.Expect(err).To(HaveOccurred()) g.Expect(err.Error()).To(HaveSuffix(`function "fname" not defined`)) // Set expected function (but not variable) d.Funcs["fname"] = func(s string) string { return "test-" + s } - _, err = RenderTemplate(p, &d) + _, err = RenderFileTemplate(p, &d) g.Expect(err).To(HaveOccurred()) g.Expect(err.Error()).To(HaveSuffix(`has no entry for key "Namespace"`)) // now we can render d.Data["Namespace"] = "myns" - o, err := RenderTemplate(p, &d) + o, err := RenderFileTemplate(p, &d) g.Expect(err).NotTo(HaveOccurred()) g.Expect(o[0].GetName()).To(Equal("test-podname")) @@ -95,7 +95,7 @@ func TestTemplateWithEmptyObject(t *testing.T) { d := MakeRenderData() d.Data["Enable"] = true - o, err := RenderTemplate(p, &d) + o, err := RenderFileTemplate(p, &d) g.Expect(err).NotTo(HaveOccurred()) g.Expect(len(o)).To(Equal(2))