From 752b424b8d74d036ff67b33530567d862df98a1a Mon Sep 17 00:00:00 2001 From: Alexander Yastrebov Date: Fri, 20 Oct 2023 13:33:33 +0200 Subject: [PATCH] provisioner: add json template function This change adds `json` function that enables use of json-formatted strings in templates. This could be used to define structured configuration values or repeated chunks in templates that require modification of several values, see provisiner/testdata/json.template.yaml for and example use. Signed-off-by: Alexander Yastrebov --- provisioner/template.go | 7 ++++ provisioner/template_test.go | 49 +++++++++++++++++++++++++ provisioner/testdata/json.expected.yaml | 37 +++++++++++++++++++ provisioner/testdata/json.template.yaml | 23 ++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 provisioner/testdata/json.expected.yaml create mode 100644 provisioner/testdata/json.template.yaml diff --git a/provisioner/template.go b/provisioner/template.go index fd7540bc..7561f106 100644 --- a/provisioner/template.go +++ b/provisioner/template.go @@ -6,6 +6,7 @@ import ( "crypto/x509" "encoding/base64" "encoding/binary" + "encoding/json" "encoding/pem" "errors" "fmt" @@ -113,6 +114,7 @@ func renderTemplate(context *templateContext, file string) (string, error) { "azID": azID, "azCount": azCount, "split": split, + "json": parseJSON, "mountUnitName": mountUnitName, "accountID": accountID, "portRanges": portRanges, @@ -294,6 +296,11 @@ func accountID(account string) (string, error) { return items[1], nil } +func parseJSON(input string) (result interface{}, err error) { + err = json.Unmarshal([]byte(input), &result) + return +} + type HostPort struct { Host string Port string diff --git a/provisioner/template_test.go b/provisioner/template_test.go index ddefd7fb..4ea51ce5 100644 --- a/provisioner/template_test.go +++ b/provisioner/template_test.go @@ -2,6 +2,7 @@ package provisioner import ( "fmt" + "os" "strconv" "testing" @@ -1164,3 +1165,51 @@ func TestNodePoolGroupsProfile(t *testing.T) { }) } } + +func TestJson(t *testing.T) { + t.Run("object", func(t *testing.T) { + result, err := renderSingle( + t, + `{{ with json .Values.data }}name={{ .name }} value={{ .value }}{{end}}`, + `{"name": "foo", "value": "bar"}`) + + require.NoError(t, err) + require.Equal(t, "name=foo value=bar", result) + }) + + t.Run("range over array", func(t *testing.T) { + result, err := renderSingle( + t, + `{{ range json .Values.data }}{{ .name }}={{ .value }} {{end}}`, + `[{"name": "foo", "value": "bar"}, {"name": "baz", "value": "qux"}]`) + + require.NoError(t, err) + require.Equal(t, "foo=bar baz=qux ", result) + }) + + t.Run("range over object", func(t *testing.T) { + result, err := renderSingle( + t, + `{{ range $key, $value := json .Values.data }}{{ $key }}={{ $value }} {{end}}`, + `{"name": "foo", "value": "bar"}`) + + require.NoError(t, err) + require.Equal(t, "name=foo value=bar ", result) + }) + + t.Run("example manifest", func(t *testing.T) { + template, err := os.ReadFile("testdata/json.template.yaml") + require.NoError(t, err) + + expected, err := os.ReadFile("testdata/json.expected.yaml") + require.NoError(t, err) + + result, err := renderSingle( + t, + string(template), + "") + + require.NoError(t, err) + require.Equal(t, string(expected), result) + }) +} diff --git a/provisioner/testdata/json.expected.yaml b/provisioner/testdata/json.expected.yaml new file mode 100644 index 00000000..1ed7a108 --- /dev/null +++ b/provisioner/testdata/json.expected.yaml @@ -0,0 +1,37 @@ + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "stable" + namespace: kube-system + labels: + application: app + version: "v1" +spec: + + selector: + matchLabels: + deployment: "stable" + template: | + omitted for clarity + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "alpha" + namespace: kube-system + labels: + application: app + version: "v2" +spec: + + replicas: 1 + + selector: + matchLabels: + deployment: "alpha" + template: | + omitted for clarity + diff --git a/provisioner/testdata/json.template.yaml b/provisioner/testdata/json.template.yaml new file mode 100644 index 00000000..1a0dd732 --- /dev/null +++ b/provisioner/testdata/json.template.yaml @@ -0,0 +1,23 @@ +{{ range json `[ + {"name": "stable", "version": "v1"}, + {"name": "alpha", "version": "v2", "replicas": 1} +]` }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .name }}" + namespace: kube-system + labels: + application: app + version: "{{ .version }}" +spec: +{{ if index . "replicas" }} + replicas: {{ .replicas }} +{{ end }} + selector: + matchLabels: + deployment: "{{ .name }}" + template: | + omitted for clarity +{{ end }}