From ad4eef7eaca0ba7e4325368153155d85677753e8 Mon Sep 17 00:00:00 2001 From: Ye Cao Date: Mon, 17 Jul 2023 15:49:56 +0800 Subject: [PATCH] * Add an option for enable/disable webhook for a standard operator generated by kubebuilder. * Use regular expressions to match the containerPort of the webhook. Signed-off-by: Ye Cao --- README.md | 1 + cmd/helmify/flags.go | 2 ++ pkg/config/config.go | 3 +++ pkg/processor/deployment/deployment.go | 27 ++++++++++++++++++++++++++ pkg/processor/service/service.go | 4 ++++ pkg/processor/webhook/cert.go | 23 ++++++++++++++++------ pkg/processor/webhook/issuer.go | 15 +++++++++++--- pkg/processor/webhook/mutating.go | 17 ++++++++++++---- pkg/processor/webhook/validating.go | 17 ++++++++++++---- 9 files changed, 92 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 590a12e..430ad0a 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,7 @@ Usage: | -cert-manager-version | Allows the user to specify cert-manager subchart version. Only useful with cert-manager-as-subchart. (default "v1.12.2") | `helmify -cert-manager-version=v1.12.2` | | -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`| ## Status Supported k8s resources: - Deployment, DaemonSet, StatefulSet diff --git a/cmd/helmify/flags.go b/cmd/helmify/flags.go index 39d94d0..7534afb 100644 --- a/cmd/helmify/flags.go +++ b/cmd/helmify/flags.go @@ -70,6 +70,8 @@ func ReadFlags() config.Config { 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.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") + flag.Parse() if h || help { fmt.Print(helpText) diff --git a/pkg/config/config.go b/pkg/config/config.go index cb314da..b0f9a8a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -2,6 +2,7 @@ package config import ( "fmt" + "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/util/validation" ) @@ -40,6 +41,8 @@ type Config struct { OriginalName bool // PreserveNs retains the namespaces on the Kubernetes manifests PreserveNs bool + // AddWebhookOption enables the generation of a webhook option in values.yamlß + AddWebhookOption bool } func (c *Config) Validate() error { diff --git a/pkg/processor/deployment/deployment.go b/pkg/processor/deployment/deployment.go index 9e7b2bd..ecbe0e2 100644 --- a/pkg/processor/deployment/deployment.go +++ b/pkg/processor/deployment/deployment.go @@ -129,6 +129,9 @@ func (d deployment) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstr if err != nil { return true, nil, err } + if appMeta.Config().AddWebhookOption { + spec = addWebhookOption(spec) + } spec = replaceSingleQuotes(spec) @@ -159,6 +162,30 @@ func replaceSingleQuotes(s string) string { return r.ReplaceAllString(s, "${1}") } +func addWebhookOption(manifest string) string { + webhookOptionHeader := " {{- if .Values.webhook.enabled }}" + webhookOptionFooter := " {{- end }}" + volumes := ` - name: cert + secret: + defaultMode: 420 + secretName: webhook-server-cert` + volumeMounts := ` - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true` + manifest = strings.ReplaceAll(manifest, volumes, fmt.Sprintf("%s\n%s\n%s", + webhookOptionHeader, volumes, webhookOptionFooter)) + manifest = strings.ReplaceAll(manifest, volumeMounts, fmt.Sprintf("%s\n%s\n%s", + webhookOptionHeader, volumeMounts, webhookOptionFooter)) + + re := regexp.MustCompile(` - containerPort: \d+ + name: webhook-server + protocol: TCP`) + + manifest = re.ReplaceAllString(manifest, fmt.Sprintf("%s\n%s\n%s", webhookOptionHeader, + re.FindString(manifest), webhookOptionFooter)) + return manifest +} + func processReplicas(name string, deployment *appsv1.Deployment, values *helmify.Values) (string, error) { if deployment.Spec.Replicas == nil { return "", nil diff --git a/pkg/processor/service/service.go b/pkg/processor/service/service.go index a23b5dc..7a22348 100644 --- a/pkg/processor/service/service.go +++ b/pkg/processor/service/service.go @@ -94,8 +94,12 @@ func (r svc) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured } ports[i] = pMap } + _ = unstructured.SetNestedSlice(values, ports, shortNameCamel, "ports") res := meta + fmt.Sprintf(svcTempSpec, shortNameCamel, selector, appMeta.ChartName()) + if shortNameCamel == "webhookService" && appMeta.Config().AddWebhookOption { + res = fmt.Sprintf("{{- if .Values.webhook.enabled }}\n%s\n{{- end }}", res) + } return true, &result{ name: shortName, data: res, diff --git a/pkg/processor/webhook/cert.go b/pkg/processor/webhook/cert.go index 65f5c7c..f09a61e 100644 --- a/pkg/processor/webhook/cert.go +++ b/pkg/processor/webhook/cert.go @@ -15,7 +15,9 @@ import ( ) const ( - certTempl = `apiVersion: cert-manager.io/v1 + WebhookHeader = `{{- if .Values.webhook.enabled }}` + WebhookFooter = `{{- end }}` + certTempl = `apiVersion: cert-manager.io/v1 kind: Certificate metadata: name: {{ include "%[1]s.fullname" . }}-%[2]s @@ -92,16 +94,25 @@ func (c cert) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructure } else { tmpl = certTempl } + values := helmify.Values{} + if appMeta.Config().AddWebhookOption { + // Add webhook.enabled value to values.yaml + _, _ = values.Add(true, "webhook", "enabled") + + tmpl = fmt.Sprintf("%s\n%s\n%s", WebhookHeader, tmpl, WebhookFooter) + } res := fmt.Sprintf(tmpl, appMeta.ChartName(), name, string(spec)) return true, &certResult{ - name: name, - data: []byte(res), + name: name, + data: []byte(res), + values: values, }, nil } type certResult struct { - name string - data []byte + name string + data []byte + values helmify.Values } func (r *certResult) Filename() string { @@ -109,7 +120,7 @@ func (r *certResult) Filename() string { } func (r *certResult) Values() helmify.Values { - return helmify.Values{} + return r.values } func (r *certResult) Write(writer io.Writer) error { diff --git a/pkg/processor/webhook/issuer.go b/pkg/processor/webhook/issuer.go index 196c11e..6e5d5b6 100644 --- a/pkg/processor/webhook/issuer.go +++ b/pkg/processor/webhook/issuer.go @@ -53,6 +53,7 @@ func (i issuer) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructu return false, nil, nil } name := appMeta.TrimName(obj.GetName()) + spec, _ := yaml.Marshal(obj.Object["spec"]) spec = yamlformat.Indent(spec, 2) spec = bytes.TrimRight(spec, "\n ") @@ -62,6 +63,13 @@ func (i issuer) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructu } else { tmpl = issuerTempl } + values := helmify.Values{} + if appMeta.Config().AddWebhookOption { + // Add webhook.enabled value to values.yaml + _, _ = values.Add(true, "webhook", "enabled") + + tmpl = fmt.Sprintf("%s\n%s\n%s", WebhookHeader, tmpl, WebhookFooter) + } res := fmt.Sprintf(tmpl, appMeta.ChartName(), name, string(spec)) return true, &issResult{ name: name, @@ -70,8 +78,9 @@ func (i issuer) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructu } type issResult struct { - name string - data []byte + name string + data []byte + values helmify.Values } func (r *issResult) Filename() string { @@ -79,7 +88,7 @@ func (r *issResult) Filename() string { } func (r *issResult) Values() helmify.Values { - return helmify.Values{} + return r.values } func (r *issResult) Write(writer io.Writer) error { diff --git a/pkg/processor/webhook/mutating.go b/pkg/processor/webhook/mutating.go index 25f2666..465dec8 100644 --- a/pkg/processor/webhook/mutating.go +++ b/pkg/processor/webhook/mutating.go @@ -65,7 +65,15 @@ func (w mwh) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured } certName = strings.TrimPrefix(certName, appMeta.Namespace()+"/") certName = appMeta.TrimName(certName) - res := fmt.Sprintf(mwhTempl, appMeta.ChartName(), name, certName, string(webhooks)) + tmpl := mwhTempl + values := helmify.Values{} + if appMeta.Config().AddWebhookOption { + // Add webhook.enabled value to values.yaml + _, _ = values.Add(true, "webhook", "enabled") + + tmpl = fmt.Sprintf("%s\n%s\n%s", WebhookHeader, mwhTempl, WebhookFooter) + } + res := fmt.Sprintf(tmpl, appMeta.ChartName(), name, certName, string(webhooks)) return true, &mwhResult{ name: name, data: []byte(res), @@ -73,8 +81,9 @@ func (w mwh) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured } type mwhResult struct { - name string - data []byte + name string + data []byte + values helmify.Values } func (r *mwhResult) Filename() string { @@ -82,7 +91,7 @@ func (r *mwhResult) Filename() string { } func (r *mwhResult) Values() helmify.Values { - return helmify.Values{} + return r.values } func (r *mwhResult) Write(writer io.Writer) error { diff --git a/pkg/processor/webhook/validating.go b/pkg/processor/webhook/validating.go index 7617cec..f9ca207 100644 --- a/pkg/processor/webhook/validating.go +++ b/pkg/processor/webhook/validating.go @@ -65,7 +65,15 @@ func (w vwh) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured } certName = strings.TrimPrefix(certName, appMeta.Namespace()+"/") certName = appMeta.TrimName(certName) - res := fmt.Sprintf(vwhTempl, appMeta.ChartName(), name, certName, string(webhooks)) + tmpl := vwhTempl + values := helmify.Values{} + if appMeta.Config().AddWebhookOption { + // Add webhook.enabled value to values.yaml + _, _ = values.Add(true, "webhook", "enabled") + + tmpl = fmt.Sprintf("%s\n%s\n%s", WebhookHeader, mwhTempl, WebhookFooter) + } + res := fmt.Sprintf(tmpl, appMeta.ChartName(), name, certName, string(webhooks)) return true, &vwhResult{ name: name, data: []byte(res), @@ -73,8 +81,9 @@ func (w vwh) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured } type vwhResult struct { - name string - data []byte + name string + data []byte + values helmify.Values } func (r *vwhResult) Filename() string { @@ -82,7 +91,7 @@ func (r *vwhResult) Filename() string { } func (r *vwhResult) Values() helmify.Values { - return helmify.Values{} + return r.values } func (r *vwhResult) Write(writer io.Writer) error {