From 2c7f288a9d70008022940499a059099bb0120a2f Mon Sep 17 00:00:00 2001 From: Camila Macedo <7708031+camilamacedo86@users.noreply.github.com> Date: Mon, 30 Dec 2024 09:12:55 +0000 Subject: [PATCH] (helm/v1alpha1) - fix webhook generation by removing data from helm chart values This commit changes the code implementation to not generate the webhook values in the helm chart values. Instead only expose on the values to enable or not webhooks --- .../optional/helm/v1alpha/scaffolds/init.go | 116 +++++++--------- .../chart-templates/webhook/webhook.go | 125 +++++++----------- .../scaffolds/internal/templates/values.go | 44 +----- pkg/plugins/optional/helm/webhookYAML.go | 35 ----- .../chart/templates/webhook/webhooks.yaml | 90 ++----------- .../dist/chart/values.yaml | 18 --- 6 files changed, 111 insertions(+), 317 deletions(-) delete mode 100644 pkg/plugins/optional/helm/webhookYAML.go diff --git a/pkg/plugins/optional/helm/v1alpha/scaffolds/init.go b/pkg/plugins/optional/helm/v1alpha/scaffolds/init.go index 513e78bb0de..1fff284b2d7 100644 --- a/pkg/plugins/optional/helm/v1alpha/scaffolds/init.go +++ b/pkg/plugins/optional/helm/v1alpha/scaffolds/init.go @@ -32,9 +32,8 @@ import ( "sigs.k8s.io/kubebuilder/v4/pkg/plugin" "sigs.k8s.io/kubebuilder/v4/pkg/plugins" "sigs.k8s.io/kubebuilder/v4/pkg/plugins/golang/deploy-image/v1alpha1" - "sigs.k8s.io/kubebuilder/v4/pkg/plugins/optional/helm" "sigs.k8s.io/kubebuilder/v4/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates" - chart_templates "sigs.k8s.io/kubebuilder/v4/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/chart-templates" + chartTemplates "sigs.k8s.io/kubebuilder/v4/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/chart-templates" templatescertmanager "sigs.k8s.io/kubebuilder/v4/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/chart-templates/cert-manager" "sigs.k8s.io/kubebuilder/v4/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/chart-templates/manager" templatesmetrics "sigs.k8s.io/kubebuilder/v4/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/chart-templates/metrics" @@ -70,11 +69,9 @@ func (s *initScaffolder) InjectFS(fs machinery.Filesystem) { func (s *initScaffolder) Scaffold() error { log.Println("Generating Helm Chart to distribute project") - // Extract Images scaffolded with DeployImage to add ENVVAR to the values imagesEnvVars := s.getDeployImagesEnvVars() - // Extract webhooks from generated YAML files (generated by controller-gen) - webhooks, err := extractWebhooksFromGeneratedFiles() + webhooks, err := s.extractWebhooks() if err != nil { return fmt.Errorf("failed to extract webhooks: %w", err) } @@ -88,12 +85,11 @@ func (s *initScaffolder) Scaffold() error { &templates.HelmChart{}, &templates.HelmValues{ HasWebhooks: len(webhooks) > 0, - Webhooks: webhooks, DeployImages: imagesEnvVars, Force: s.force, }, &templates.HelmIgnore{}, - &chart_templates.HelmHelpers{}, + &chartTemplates.HelmHelpers{}, &manager.ManagerDeployment{ Force: s.force, DeployImages: len(imagesEnvVars) > 0, @@ -105,8 +101,12 @@ func (s *initScaffolder) Scaffold() error { } if len(webhooks) > 0 { - buildScaffold = append(buildScaffold, &templateswebhooks.WebhookTemplate{}) - buildScaffold = append(buildScaffold, &templateswebhooks.WebhookService{}) + buildScaffold = append(buildScaffold, + &templateswebhooks.WebhookTemplate{ + Webhooks: webhooks, + }, + &templateswebhooks.WebhookService{}, + ) } if err := scaffold.Execute(buildScaffold...); err != nil { @@ -146,87 +146,65 @@ func (s *initScaffolder) getDeployImagesEnvVars() map[string]string { return deployImages } -// Extract webhooks from manifests.yaml file -func extractWebhooksFromGeneratedFiles() ([]helm.WebhookYAML, error) { - var webhooks []helm.WebhookYAML +// extractWebhooks reads webhook YAML configurations and converts them to Webhook structs. +func (s *initScaffolder) extractWebhooks() ([]templateswebhooks.Webhook, error) { + var webhooks []templateswebhooks.Webhook manifestFile := "config/webhook/manifests.yaml" - if _, err := os.Stat(manifestFile); err == nil { - content, err := os.ReadFile(manifestFile) - if err != nil { - return nil, fmt.Errorf("failed to read manifests.yaml: %w", err) - } - // Process the content to extract webhooks - webhooks = append(webhooks, extractWebhookYAML(content)...) - } else { - // Return empty if no webhooks were found + if _, err := os.Stat(manifestFile); os.IsNotExist(err) { + log.Printf("No webhook manifests found at %s", manifestFile) return webhooks, nil } - return webhooks, nil -} - -// extractWebhookYAML parses the webhook YAML content and returns a list of WebhookYAML -func extractWebhookYAML(content []byte) []helm.WebhookYAML { - var webhooks []helm.WebhookYAML - - type WebhookConfig struct { - Kind string `yaml:"kind"` - Webhooks []struct { - Name string `yaml:"name"` - ClientConfig struct { - Service struct { - Name string `yaml:"name"` - Namespace string `yaml:"namespace"` - Path string `yaml:"path"` - } `yaml:"service"` - CABundle string `yaml:"caBundle"` - } `yaml:"clientConfig"` - Rules []helm.WebhookRule `yaml:"rules"` - FailurePolicy string `yaml:"failurePolicy"` - SideEffects string `yaml:"sideEffects"` - AdmissionReviewVersions []string `yaml:"admissionReviewVersions"` - } `yaml:"webhooks"` + content, err := os.ReadFile(manifestFile) + if err != nil { + return nil, fmt.Errorf("failed to read %s: %w", manifestFile, err) } - // Split the input into different documents (to handle multiple YAML docs in one file) docs := strings.Split(string(content), "---") - for _, doc := range docs { - var webhookConfig WebhookConfig + var webhookConfig struct { + Kind string `yaml:"kind"` + Webhooks []struct { + Name string `yaml:"name"` + ClientConfig struct { + Service struct { + Name string `yaml:"name"` + Namespace string `yaml:"namespace"` + Path string `yaml:"path"` + } `yaml:"service"` + } `yaml:"clientConfig"` + Rules []templateswebhooks.WebhookRule `yaml:"rules"` + FailurePolicy string `yaml:"failurePolicy"` + SideEffects string `yaml:"sideEffects"` + AdmissionReviewVersions []string `yaml:"admissionReviewVersions"` + } `yaml:"webhooks"` + } + if err := yaml.Unmarshal([]byte(doc), &webhookConfig); err != nil { - log.Errorf("Error unmarshalling webhook YAML: %v", err) + log.Errorf("Error parsing webhook YAML: %v", err) continue } - // Determine the webhook type (mutating or validating) - webhookType := "unknown" + webhookType := "validating" if webhookConfig.Kind == "MutatingWebhookConfiguration" { webhookType = "mutating" - } else if webhookConfig.Kind == "ValidatingWebhookConfiguration" { - webhookType = "validating" } - // Parse each webhook and append it to the result - for _, webhook := range webhookConfig.Webhooks { - for i := range webhook.Rules { - // If apiGroups is empty, set it to [""] to ensure proper YAML output - if len(webhook.Rules[i].APIGroups) == 0 { - webhook.Rules[i].APIGroups = []string{""} - } - } - webhooks = append(webhooks, helm.WebhookYAML{ - Name: webhook.Name, + for _, w := range webhookConfig.Webhooks { + webhooks = append(webhooks, templateswebhooks.Webhook{ + Name: w.Name, Type: webhookType, - Path: webhook.ClientConfig.Service.Path, - Rules: webhook.Rules, - FailurePolicy: webhook.FailurePolicy, - SideEffects: webhook.SideEffects, - AdmissionReviewVersions: webhook.AdmissionReviewVersions, + ServiceName: w.ClientConfig.Service.Name, + Path: w.ClientConfig.Service.Path, + FailurePolicy: w.FailurePolicy, + SideEffects: w.SideEffects, + AdmissionReviewVersions: w.AdmissionReviewVersions, + Rules: w.Rules, }) } } - return webhooks + return webhooks, nil } // Helper function to copy files from config/ to dist/chart/templates/ diff --git a/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/chart-templates/webhook/webhook.go b/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/chart-templates/webhook/webhook.go index f22f71129a4..24c58be7810 100644 --- a/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/chart-templates/webhook/webhook.go +++ b/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/chart-templates/webhook/webhook.go @@ -27,6 +27,8 @@ var _ machinery.Template = &WebhookTemplate{} type WebhookTemplate struct { machinery.TemplateMixin machinery.ProjectNameMixin + + Webhooks []Webhook } // SetTemplateDefaults sets default configuration for the webhook template @@ -42,12 +44,32 @@ func (f *WebhookTemplate) SetTemplateDefaults() error { return nil } -const webhookTemplate = `{{` + "`" + `{{- if .Values.webhook.enable }}` + "`" + `}} +// Webhook helps generate the bollerplate with the Webhook values +type Webhook struct { + ServiceName string + Name string + Path string + Type string + FailurePolicy string + SideEffects string + AdmissionReviewVersions []string + Rules []WebhookRule +} +// WebhookRule to help map the rules +type WebhookRule struct { + Operations []string + APIGroups []string + APIVersions []string + Resources []string +} + +const webhookTemplate = `{{` + "`" + `{{- if .Values.webhook.enable }}` + "`" + `}} +{{- range .Webhooks }} apiVersion: admissionregistration.k8s.io/v1 -kind: MutatingWebhookConfiguration +kind: {{ if eq .Type "mutating" }}MutatingWebhookConfiguration{{ else }}ValidatingWebhookConfiguration{{ end }} metadata: - name: {{ .ProjectName }}-mutating-webhook-configuration + name: {{ .Name }} namespace: {{ "{{ .Release.Namespace }}" }} annotations: {{` + "`" + `{{- if .Values.certmanager.enable }}` + "`" + `}} @@ -56,87 +78,38 @@ metadata: labels: {{ "{{- include \"chart.labels\" . | nindent 4 }}" }} webhooks: - {{` + "`" + `{{- range .Values.webhook.services }}` + "`" + `}} - {{` + "`" + `{{- if eq .type "mutating" }}` + "`" + `}} - - name: {{` + "`" + `{{ .name }}` + "`" + `}} - clientConfig: - service: - name: {{ .ProjectName }}-webhook-service - namespace: {{` + "`" + `{{ $.Release.Namespace }}` + "`" + `}} - path: {{` + "`" + `{{ .path }}` + "`" + `}} - failurePolicy: {{` + "`" + `{{ .failurePolicy }}` + "`" + `}} - sideEffects: {{` + "`" + `{{ .sideEffects }}` + "`" + `}} - admissionReviewVersions: - {{` + "`" + `{{- range .admissionReviewVersions }}` + "`" + `}} - - {{` + "`" + `{{ . }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} - rules: - {{` + "`" + `{{- range .rules }}` + "`" + `}} - - operations: - {{` + "`" + `{{- range .operations }}` + "`" + `}} - - {{` + "`" + `{{ . }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} - apiGroups: - {{` + "`" + `{{- range .apiGroups }}` + "`" + `}} - - {{` + "`" + `{{ . }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} - apiVersions: - {{` + "`" + `{{- range .apiVersions }}` + "`" + `}} - - {{` + "`" + `{{ . }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} - resources: - {{` + "`" + `{{- range .resources }}` + "`" + `}} - - {{` + "`" + `{{ . }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} ---- -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - name: {{ .ProjectName }}-validating-webhook-configuration - namespace: {{ "{{ .Release.Namespace }}" }} - annotations: - {{` + "`" + `{{- if .Values.certmanager.enable }}` + "`" + `}} - cert-manager.io/inject-ca-from: "{{` + "`" + `{{ $.Release.Namespace }}` + "`" + `}}/serving-cert" - {{` + "`" + `{{- end }}` + "`" + `}} -webhooks: - {{` + "`" + `{{- range .Values.webhook.services }}` + "`" + `}} - {{` + "`" + `{{- if eq .type "validating" }}` + "`" + `}} - - name: {{` + "`" + `{{ .name }}` + "`" + `}} + - name: {{ .Name }} clientConfig: service: - name: {{ .ProjectName }}-webhook-service - namespace: {{` + "`" + `{{ $.Release.Namespace }}` + "`" + `}} - path: {{` + "`" + `{{ .path }}` + "`" + `}} - failurePolicy: {{` + "`" + `{{ .failurePolicy }}` + "`" + `}} - sideEffects: {{` + "`" + `{{ .sideEffects }}` + "`" + `}} + name: {{ .ServiceName }} + namespace: {{ "{{ .Release.Namespace }}" }} + path: {{ .Path }} + failurePolicy: {{ .FailurePolicy }} + sideEffects: {{ .SideEffects }} admissionReviewVersions: - {{` + "`" + `{{- range .admissionReviewVersions }}` + "`" + `}} - - {{` + "`" + `{{ . }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} + {{- range .AdmissionReviewVersions }} + - {{ . }} + {{- end }} rules: - {{` + "`" + `{{- range .rules }}` + "`" + `}} + {{- range .Rules }} - operations: - {{` + "`" + `{{- range .operations }}` + "`" + `}} - - {{` + "`" + `{{ . }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} + {{- range .Operations }} + - {{ . }} + {{- end }} apiGroups: - {{` + "`" + `{{- range .apiGroups }}` + "`" + `}} - - {{` + "`" + `{{ . }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} + {{- range .APIGroups }} + - {{ . }} + {{- end }} apiVersions: - {{` + "`" + `{{- range .apiVersions }}` + "`" + `}} - - {{` + "`" + `{{ . }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} + {{- range .APIVersions }} + - {{ . }} + {{- end }} resources: - {{` + "`" + `{{- range .resources }}` + "`" + `}} - - {{` + "`" + `{{ . }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} - {{` + "`" + `{{- end }}` + "`" + `}} + {{- range .Resources }} + - {{ . }} + {{- end }} + {{- end }} --- +{{- end }} {{` + "`" + `{{- end }}` + "`" + `}} ` diff --git a/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/values.go b/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/values.go index e4874e59254..86942894636 100644 --- a/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/values.go +++ b/pkg/plugins/optional/helm/v1alpha/scaffolds/internal/templates/values.go @@ -19,7 +19,6 @@ import ( "path/filepath" "sigs.k8s.io/kubebuilder/v4/pkg/machinery" - "sigs.k8s.io/kubebuilder/v4/pkg/plugins/optional/helm" ) var _ machinery.Template = &HelmValues{} @@ -33,8 +32,6 @@ type HelmValues struct { DeployImages map[string]string // Force if true allows overwriting the scaffolded file Force bool - // Webhooks stores the webhook configurations - Webhooks []helm.WebhookYAML // HasWebhooks is true when webhooks were found in the config HasWebhooks bool } @@ -125,52 +122,13 @@ crd: # ControllerManager argument "--metrics-bind-address=:8443" is removed. metrics: enable: true -{{ if .Webhooks }} +{{ if .HasWebhooks }} # [WEBHOOKS]: Webhooks configuration # The following configuration is automatically generated from the manifests # generated by controller-gen. To update run 'make manifests' and # the edit command with the '--force' flag webhook: enable: true - services: - {{- range .Webhooks }} - - name: {{ .Name }} - type: {{ .Type }} - path: {{ .Path }} - failurePolicy: {{ .FailurePolicy }} - sideEffects: {{ .SideEffects }} - admissionReviewVersions: - {{- range .AdmissionReviewVersions }} - - {{ . }} - {{- end }} - rules: - {{- range .Rules }} - - operations: - {{- range .Operations }} - - {{ . }} - {{- end }} - apiGroups: - {{- if .APIGroups }} - {{- range .APIGroups }} - {{- if eq . "" }} - - "" - {{- else }} - - {{ . }} - {{- end }} - {{- end }} - {{- else }} - - "" - {{- end }} - apiVersions: - {{- range .APIVersions }} - - {{ . }} - {{- end }} - resources: - {{- range .Resources }} - - {{ . }} - {{- end }} - {{- end }} - {{- end }} {{ end }} # [PROMETHEUS]: To enable a ServiceMonitor to export metrics to Prometheus set true prometheus: diff --git a/pkg/plugins/optional/helm/webhookYAML.go b/pkg/plugins/optional/helm/webhookYAML.go deleted file mode 100644 index 3880fa79065..00000000000 --- a/pkg/plugins/optional/helm/webhookYAML.go +++ /dev/null @@ -1,35 +0,0 @@ -/* -Copyright 2024 The Kubernetes Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package helm - -// WebhookRule represents the rules for operations, API groups, versions, and resources -type WebhookRule struct { - Operations []string `yaml:"operations"` - APIGroups []string `yaml:"apiGroups"` - APIVersions []string `yaml:"apiVersions"` - Resources []string `yaml:"resources"` -} - -// WebhookYAML stores the details of each webhook generated by controller-gen -type WebhookYAML struct { - Name string `yaml:"name"` - Type string `yaml:"type"` - Path string `yaml:"path"` - Rules []WebhookRule `yaml:"rules"` - FailurePolicy string `yaml:"failurePolicy"` - SideEffects string `yaml:"sideEffects"` - AdmissionReviewVersions []string `yaml:"admissionReviewVersions"` -} diff --git a/testdata/project-v4-with-plugins/dist/chart/templates/webhook/webhooks.yaml b/testdata/project-v4-with-plugins/dist/chart/templates/webhook/webhooks.yaml index 429fd8d6cb0..57d80ae5f0b 100644 --- a/testdata/project-v4-with-plugins/dist/chart/templates/webhook/webhooks.yaml +++ b/testdata/project-v4-with-plugins/dist/chart/templates/webhook/webhooks.yaml @@ -1,9 +1,8 @@ {{- if .Values.webhook.enable }} - apiVersion: admissionregistration.k8s.io/v1 -kind: MutatingWebhookConfiguration +kind: ValidatingWebhookConfiguration metadata: - name: project-v4-with-plugins-mutating-webhook-configuration + name: vmemcached-v1alpha1.kb.io namespace: {{ .Release.Namespace }} annotations: {{- if .Values.certmanager.enable }} @@ -12,86 +11,25 @@ metadata: labels: {{- include "chart.labels" . | nindent 4 }} webhooks: - {{- range .Values.webhook.services }} - {{- if eq .type "mutating" }} - - name: {{ .name }} - clientConfig: - service: - name: project-v4-with-plugins-webhook-service - namespace: {{ $.Release.Namespace }} - path: {{ .path }} - failurePolicy: {{ .failurePolicy }} - sideEffects: {{ .sideEffects }} - admissionReviewVersions: - {{- range .admissionReviewVersions }} - - {{ . }} - {{- end }} - rules: - {{- range .rules }} - - operations: - {{- range .operations }} - - {{ . }} - {{- end }} - apiGroups: - {{- range .apiGroups }} - - {{ . }} - {{- end }} - apiVersions: - {{- range .apiVersions }} - - {{ . }} - {{- end }} - resources: - {{- range .resources }} - - {{ . }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} ---- -apiVersion: admissionregistration.k8s.io/v1 -kind: ValidatingWebhookConfiguration -metadata: - name: project-v4-with-plugins-validating-webhook-configuration - namespace: {{ .Release.Namespace }} - annotations: - {{- if .Values.certmanager.enable }} - cert-manager.io/inject-ca-from: "{{ $.Release.Namespace }}/serving-cert" - {{- end }} -webhooks: - {{- range .Values.webhook.services }} - {{- if eq .type "validating" }} - - name: {{ .name }} + - name: vmemcached-v1alpha1.kb.io clientConfig: service: - name: project-v4-with-plugins-webhook-service - namespace: {{ $.Release.Namespace }} - path: {{ .path }} - failurePolicy: {{ .failurePolicy }} - sideEffects: {{ .sideEffects }} + name: webhook-service + namespace: {{ .Release.Namespace }} + path: /validate-example-com-testproject-org-v1alpha1-memcached + failurePolicy: Fail + sideEffects: None admissionReviewVersions: - {{- range .admissionReviewVersions }} - - {{ . }} - {{- end }} + - v1 rules: - {{- range .rules }} - operations: - {{- range .operations }} - - {{ . }} - {{- end }} + - CREATE + - UPDATE apiGroups: - {{- range .apiGroups }} - - {{ . }} - {{- end }} + - example.com.testproject.org apiVersions: - {{- range .apiVersions }} - - {{ . }} - {{- end }} + - v1alpha1 resources: - {{- range .resources }} - - {{ . }} - {{- end }} - {{- end }} - {{- end }} - {{- end }} + - memcacheds --- {{- end }} diff --git a/testdata/project-v4-with-plugins/dist/chart/values.yaml b/testdata/project-v4-with-plugins/dist/chart/values.yaml index 5e9b98e16b5..89757cd37f7 100644 --- a/testdata/project-v4-with-plugins/dist/chart/values.yaml +++ b/testdata/project-v4-with-plugins/dist/chart/values.yaml @@ -72,24 +72,6 @@ metrics: # the edit command with the '--force' flag webhook: enable: true - services: - - name: vmemcached-v1alpha1.kb.io - type: validating - path: /validate-example-com-testproject-org-v1alpha1-memcached - failurePolicy: Fail - sideEffects: None - admissionReviewVersions: - - v1 - rules: - - operations: - - CREATE - - UPDATE - apiGroups: - - example.com.testproject.org - apiVersions: - - v1alpha1 - resources: - - memcacheds # [PROMETHEUS]: To enable a ServiceMonitor to export metrics to Prometheus set true prometheus: