From c9806044a5da513b1ba598d0c8e11d1ed5913dc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Hern=C3=A1ndez=20N=C3=A1jera-Ales=C3=B3n?= Date: Thu, 21 Nov 2024 16:56:30 +0100 Subject: [PATCH 1/5] add support for optional secrets using flag optional-secrets --- cmd/helmify/flags.go | 3 +++ pkg/config/config.go | 2 ++ pkg/helmify/values.go | 14 +++++++---- pkg/helmify/values_test.go | 4 +-- pkg/processor/secret/secret.go | 46 +++++++++++++++++++++++----------- 5 files changed, 47 insertions(+), 22 deletions(-) diff --git a/cmd/helmify/flags.go b/cmd/helmify/flags.go index 7534afb2..30ea9570 100644 --- a/cmd/helmify/flags.go +++ b/cmd/helmify/flags.go @@ -53,6 +53,7 @@ func (i *arrayFlags) Set(value string) error { // ReadFlags command-line flags into app config. func ReadFlags() config.Config { files := arrayFlags{} + optionalSecrets := arrayFlags{} result := config.Config{} var h, help, version, crd, preservens bool flag.BoolVar(&h, "h", false, "Print help. Example: helmify -h") @@ -69,6 +70,7 @@ func ReadFlags() config.Config { flag.BoolVar(&result.FilesRecursively, "r", false, "Scan dirs from -f option recursively") flag.BoolVar(&result.OriginalName, "original-name", false, "Use the object's original name instead of adding the chart's release name as the common prefix.") flag.Var(&files, "f", "File or directory containing k8s manifests") + flag.Var(&optionalSecrets, "optional-secrets", "List of secrets to be templated as optional (their values will not be required).") flag.BoolVar(&preservens, "preserve-ns", false, "Use the object's original namespace instead of adding all the resources to a common namespace") flag.BoolVar(&result.AddWebhookOption, "add-webhook-option", false, "Allows the user to add webhook option in values.yaml") @@ -94,5 +96,6 @@ func ReadFlags() config.Config { result.PreserveNs = true } result.Files = files + result.OptionalSecrets = optionalSecrets return result } diff --git a/pkg/config/config.go b/pkg/config/config.go index b0f9a8ad..6ad3789e 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -43,6 +43,8 @@ type Config struct { PreserveNs bool // AddWebhookOption enables the generation of a webhook option in values.yamlß AddWebhookOption bool + // OptionalSecrets - list of secrets that are optional and should only be generated if values are given + OptionalSecrets []string } func (c *Config) Validate() error { diff --git a/pkg/helmify/values.go b/pkg/helmify/values.go index 86dfe7f6..68fadb6a 100644 --- a/pkg/helmify/values.go +++ b/pkg/helmify/values.go @@ -1,11 +1,12 @@ package helmify import ( - "dario.cat/mergo" "fmt" "strconv" "strings" + "dario.cat/mergo" + "github.com/iancoleman/strcase" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -71,12 +72,15 @@ func (v *Values) AddYaml(value interface{}, indent int, newLine bool, name ...st // AddSecret - adds empty value to values and returns its helm template representation {{ required "" .Values. }}. // Set toBase64=true for Secret data to be base64 encoded and set false for Secret stringData. -func (v *Values) AddSecret(toBase64 bool, name ...string) (string, error) { +func (v *Values) AddSecret(toBase64 bool, optionalSecret bool, name ...string) (string, error) { name = toCamelCase(name) nameStr := strings.Join(name, ".") - err := unstructured.SetNestedField(*v, "", name...) - if err != nil { - return "", fmt.Errorf("%w: unable to set value: %v", err, nameStr) + var err error = nil + if !optionalSecret { + err = unstructured.SetNestedField(*v, "", name...) + if err != nil { + return "", fmt.Errorf("%w: unable to set value: %v", err, nameStr) + } } res := fmt.Sprintf(`{{ required "%[1]s is required" .Values.%[1]s`, nameStr) if toBase64 { diff --git a/pkg/helmify/values_test.go b/pkg/helmify/values_test.go index 6d1c0107..ac54be69 100644 --- a/pkg/helmify/values_test.go +++ b/pkg/helmify/values_test.go @@ -71,13 +71,13 @@ func TestValues_Add(t *testing.T) { func TestValues_AddSecret(t *testing.T) { t.Run("add base64 enc secret", func(t *testing.T) { testVal := Values{} - res, err := testVal.AddSecret(true, "a", "b") + res, err := testVal.AddSecret(true, true, "a", "b") assert.NoError(t, err) assert.Contains(t, res, "b64enc") }) t.Run("add not encoded secret", func(t *testing.T) { testVal := Values{} - res, err := testVal.AddSecret(false, "a", "b") + res, err := testVal.AddSecret(true, true, "a", "b") assert.NoError(t, err) assert.NotContains(t, res, "b64enc") }) diff --git a/pkg/processor/secret/secret.go b/pkg/processor/secret/secret.go index 7dec4de9..dafeb5e2 100644 --- a/pkg/processor/secret/secret.go +++ b/pkg/processor/secret/secret.go @@ -2,11 +2,13 @@ package secret import ( "fmt" - "github.com/arttor/helmify/pkg/format" "io" + "slices" "strings" "text/template" + "github.com/arttor/helmify/pkg/format" + "github.com/arttor/helmify/pkg/processor" "github.com/arttor/helmify/pkg/helmify" @@ -18,17 +20,24 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" ) -var secretTempl, _ = template.New("secret").Parse( - `{{ .Meta }} -{{- if .Data }} -{{ .Data }} +// Template uses << and >> as delimiters because if we used the default ones "{{" and ""}}" +// we would not be able ton insert {{- end }} in the template. +var secretTempl, _ = template.New("secret").Delims("<<", ">>").Parse(`<<- if .Optional >> +<< .Optional >> +<<- end >> +<< .Meta >> +<<- if .Data >> +<< .Data >> +<<- end >> +<<- if .StringData >> +<< .StringData >> +<<- end >> +<<- if .Type >> +<< .Type >> +<<- end >> +<<- if .Optional >> {{- end }} -{{- if .StringData }} -{{ .StringData }} -{{- end }} -{{- if .Type }} -{{ .Type }} -{{- end }}`) +<<- end >>`) var configMapGVC = schema.GroupVersionKind{ Group: "", @@ -60,7 +69,12 @@ func (d secret) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructu name := appMeta.TrimName(obj.GetName()) nameCamelCase := strcase.ToLowerCamel(name) - + isOptional := slices.Contains(appMeta.Config().OptionalSecrets, obj.GetName()) + //isOptional := false + optionalData := "" + if isOptional { + optionalData = fmt.Sprintf("{{- if not (empty .Values.%s) }}", nameCamelCase) + } secretType := string(sec.Type) if secretType != "" { secretType, err = yamlformat.Marshal(map[string]interface{}{"type": secretType}, 0) @@ -77,7 +91,7 @@ func (d secret) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructu if key == strings.ToUpper(key) { keyCamelCase = strcase.ToLowerCamel(strings.ToLower(key)) } - templatedName, err := values.AddSecret(true, nameCamelCase, keyCamelCase) + templatedName, err := values.AddSecret(true, isOptional, nameCamelCase, keyCamelCase) if err != nil { return true, nil, fmt.Errorf("%w: unable add secret to values", err) } @@ -98,7 +112,7 @@ func (d secret) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructu if key == strings.ToUpper(key) { keyCamelCase = strcase.ToLowerCamel(strings.ToLower(key)) } - templatedName, err := values.AddSecret(false, nameCamelCase, keyCamelCase) + templatedName, err := values.AddSecret(false, isOptional, nameCamelCase, keyCamelCase) if err != nil { return true, nil, fmt.Errorf("%w: unable add secret to values", err) } @@ -120,7 +134,8 @@ func (d secret) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructu Meta string Data string StringData string - }{Type: secretType, Meta: meta, Data: data, StringData: stringData}, + Optional string + }{Type: secretType, Meta: meta, Data: data, StringData: stringData, Optional: optionalData}, values: values, }, nil } @@ -132,6 +147,7 @@ type result struct { Meta string Data string StringData string + Optional string } values helmify.Values } From fc186bfdf01d8085bf5001ffbcb8cfc5598da4cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Hern=C3=A1ndez=20N=C3=A1jera-Ales=C3=B3n?= Date: Thu, 21 Nov 2024 17:40:06 +0100 Subject: [PATCH 2/5] fix bad tests --- pkg/helmify/values_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/helmify/values_test.go b/pkg/helmify/values_test.go index ac54be69..b5f85d3b 100644 --- a/pkg/helmify/values_test.go +++ b/pkg/helmify/values_test.go @@ -71,13 +71,13 @@ func TestValues_Add(t *testing.T) { func TestValues_AddSecret(t *testing.T) { t.Run("add base64 enc secret", func(t *testing.T) { testVal := Values{} - res, err := testVal.AddSecret(true, true, "a", "b") + res, err := testVal.AddSecret(true, false, "a", "b") assert.NoError(t, err) assert.Contains(t, res, "b64enc") }) t.Run("add not encoded secret", func(t *testing.T) { testVal := Values{} - res, err := testVal.AddSecret(true, true, "a", "b") + res, err := testVal.AddSecret(false, false, "a", "b") assert.NoError(t, err) assert.NotContains(t, res, "b64enc") }) From 4239542cee47b44fe06c4ac19c4ab17aea09606f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Hern=C3=A1ndez=20N=C3=A1jera-Ales=C3=B3n?= Date: Fri, 22 Nov 2024 08:52:49 +0100 Subject: [PATCH 3/5] add examples to PR --- examples/app/templates/my-secret-ca.yaml | 1 + examples/app/templates/my-secret-vars.yaml | 1 + examples/operator/templates/secret-ca.yaml | 1 + examples/operator/templates/secret-registry-credentials.yaml | 1 + examples/operator/templates/secret-vars.yaml | 1 + 5 files changed, 5 insertions(+) diff --git a/examples/app/templates/my-secret-ca.yaml b/examples/app/templates/my-secret-ca.yaml index 19ee3fb2..ed357928 100644 --- a/examples/app/templates/my-secret-ca.yaml +++ b/examples/app/templates/my-secret-ca.yaml @@ -1,3 +1,4 @@ + apiVersion: v1 kind: Secret metadata: diff --git a/examples/app/templates/my-secret-vars.yaml b/examples/app/templates/my-secret-vars.yaml index aec5b231..4e3f1807 100644 --- a/examples/app/templates/my-secret-vars.yaml +++ b/examples/app/templates/my-secret-vars.yaml @@ -1,3 +1,4 @@ + apiVersion: v1 kind: Secret metadata: diff --git a/examples/operator/templates/secret-ca.yaml b/examples/operator/templates/secret-ca.yaml index ddacf08a..d890f991 100644 --- a/examples/operator/templates/secret-ca.yaml +++ b/examples/operator/templates/secret-ca.yaml @@ -1,3 +1,4 @@ + apiVersion: v1 kind: Secret metadata: diff --git a/examples/operator/templates/secret-registry-credentials.yaml b/examples/operator/templates/secret-registry-credentials.yaml index ef4fdad7..47851d7f 100644 --- a/examples/operator/templates/secret-registry-credentials.yaml +++ b/examples/operator/templates/secret-registry-credentials.yaml @@ -1,3 +1,4 @@ + apiVersion: v1 kind: Secret metadata: diff --git a/examples/operator/templates/secret-vars.yaml b/examples/operator/templates/secret-vars.yaml index f77878a2..677c2765 100644 --- a/examples/operator/templates/secret-vars.yaml +++ b/examples/operator/templates/secret-vars.yaml @@ -1,3 +1,4 @@ + apiVersion: v1 kind: Secret metadata: From ac7c00a96a7c64fb2eea5168fb12b64ab9835224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Hern=C3=A1ndez=20N=C3=A1jera-Ales=C3=B3n?= Date: Tue, 17 Dec 2024 16:12:04 +0100 Subject: [PATCH 4/5] fix bad firstline in secret --- examples/operator/templates/secret-ca.yaml | 1 - .../operator/templates/secret-registry-credentials.yaml | 1 - examples/operator/templates/secret-vars.yaml | 1 - pkg/processor/secret/secret.go | 7 +++---- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/examples/operator/templates/secret-ca.yaml b/examples/operator/templates/secret-ca.yaml index d890f991..ddacf08a 100644 --- a/examples/operator/templates/secret-ca.yaml +++ b/examples/operator/templates/secret-ca.yaml @@ -1,4 +1,3 @@ - apiVersion: v1 kind: Secret metadata: diff --git a/examples/operator/templates/secret-registry-credentials.yaml b/examples/operator/templates/secret-registry-credentials.yaml index 47851d7f..ef4fdad7 100644 --- a/examples/operator/templates/secret-registry-credentials.yaml +++ b/examples/operator/templates/secret-registry-credentials.yaml @@ -1,4 +1,3 @@ - apiVersion: v1 kind: Secret metadata: diff --git a/examples/operator/templates/secret-vars.yaml b/examples/operator/templates/secret-vars.yaml index 677c2765..f77878a2 100644 --- a/examples/operator/templates/secret-vars.yaml +++ b/examples/operator/templates/secret-vars.yaml @@ -1,4 +1,3 @@ - apiVersion: v1 kind: Secret metadata: diff --git a/pkg/processor/secret/secret.go b/pkg/processor/secret/secret.go index dafeb5e2..8c7b0b56 100644 --- a/pkg/processor/secret/secret.go +++ b/pkg/processor/secret/secret.go @@ -22,9 +22,9 @@ import ( // Template uses << and >> as delimiters because if we used the default ones "{{" and ""}}" // we would not be able ton insert {{- end }} in the template. -var secretTempl, _ = template.New("secret").Delims("<<", ">>").Parse(`<<- if .Optional >> +var secretTempl, _ = template.New("secret").Delims("<<", ">>").Parse(`<< if .Optional ->> << .Optional >> -<<- end >> +<< end ->> << .Meta >> <<- if .Data >> << .Data >> @@ -70,8 +70,7 @@ func (d secret) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructu name := appMeta.TrimName(obj.GetName()) nameCamelCase := strcase.ToLowerCamel(name) isOptional := slices.Contains(appMeta.Config().OptionalSecrets, obj.GetName()) - //isOptional := false - optionalData := "" + var optionalData string if isOptional { optionalData = fmt.Sprintf("{{- if not (empty .Values.%s) }}", nameCamelCase) } From 0c48b5285a615de571c1945a86868395cc4081b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20Hern=C3=A1ndez=20N=C3=A1jera-Ales=C3=B3n?= Date: Tue, 17 Dec 2024 16:33:39 +0100 Subject: [PATCH 5/5] add docs for flag and fix testcases --- README.md | 1 + examples/app/templates/my-secret-ca.yaml | 1 - examples/app/templates/my-secret-vars.yaml | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 430ad0a4..7d247e00 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ Usage: | -cert-manager-install-crd | Allows the user to install cert-manager CRD as part of the cert-manager subchart.(default "true") | `helmify -cert-manager-install-crd` | | -preserve-ns | Allows users to use the object's original namespace instead of adding all the resources to a common namespace. (default "false") | `helmify -preserve-ns` | | -add-webhook-option | Adds an option to enable/disable webhook installation | `helmify -add-webhook-option`| +| -optional-secrets | Secrets whose values should not be required by helm | `helmify -optional-secrets mysecret1,mysecret2`| ## Status Supported k8s resources: - Deployment, DaemonSet, StatefulSet diff --git a/examples/app/templates/my-secret-ca.yaml b/examples/app/templates/my-secret-ca.yaml index ed357928..19ee3fb2 100644 --- a/examples/app/templates/my-secret-ca.yaml +++ b/examples/app/templates/my-secret-ca.yaml @@ -1,4 +1,3 @@ - apiVersion: v1 kind: Secret metadata: diff --git a/examples/app/templates/my-secret-vars.yaml b/examples/app/templates/my-secret-vars.yaml index 4e3f1807..aec5b231 100644 --- a/examples/app/templates/my-secret-vars.yaml +++ b/examples/app/templates/my-secret-vars.yaml @@ -1,4 +1,3 @@ - apiVersion: v1 kind: Secret metadata: