Skip to content

Commit

Permalink
(helm/v1alpha1) - fix webhook generation by removing data from helm c…
Browse files Browse the repository at this point in the history
…hart values

This commit changes the code implementation so that the webhook values in the helm chart are not generated. Instead, only expose the values to enable or not webhooks
  • Loading branch information
camilamacedo86 committed Dec 30, 2024
1 parent 980fb71 commit 84f50b0
Show file tree
Hide file tree
Showing 8 changed files with 164 additions and 308 deletions.
143 changes: 66 additions & 77 deletions pkg/plugins/optional/helm/v1alpha/scaffolds/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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()
mutatingWebhooks, validatingWebhooks, err := s.extractWebhooksFromGeneratedFiles()
if err != nil {
return fmt.Errorf("failed to extract webhooks: %w", err)
}
Expand All @@ -83,30 +80,35 @@ func (s *initScaffolder) Scaffold() error {
machinery.WithConfig(s.config),
)

hasWebhooks := len(mutatingWebhooks) > 0 || len(validatingWebhooks) > 0
buildScaffold := []machinery.Builder{
&github.HelmChartCI{},
&templates.HelmChart{},
&templates.HelmValues{
HasWebhooks: len(webhooks) > 0,
Webhooks: webhooks,
HasWebhooks: hasWebhooks,
DeployImages: imagesEnvVars,
Force: s.force,
},
&templates.HelmIgnore{},
&chart_templates.HelmHelpers{},
&charttemplates.HelmHelpers{},
&manager.ManagerDeployment{
Force: s.force,
DeployImages: len(imagesEnvVars) > 0,
HasWebhooks: len(webhooks) > 0,
HasWebhooks: hasWebhooks,
},
&templatescertmanager.Certificate{},
&templatesmetrics.MetricsService{},
&prometheus.Monitor{},
}

if len(webhooks) > 0 {
buildScaffold = append(buildScaffold, &templateswebhooks.WebhookTemplate{})
buildScaffold = append(buildScaffold, &templateswebhooks.WebhookService{})
if len(mutatingWebhooks) > 0 || len(validatingWebhooks) > 0 {
buildScaffold = append(buildScaffold,
&templateswebhooks.WebhookTemplate{
MutatingWebhooks: mutatingWebhooks,
ValidatingWebhooks: validatingWebhooks,
},
&templateswebhooks.WebhookService{},
)
}

if err := scaffold.Execute(buildScaffold...); err != nil {
Expand Down Expand Up @@ -146,87 +148,74 @@ func (s *initScaffolder) getDeployImagesEnvVars() map[string]string {
return deployImages
}

// Extract webhooks from manifests.yaml file
func extractWebhooksFromGeneratedFiles() ([]helm.WebhookYAML, error) {
var webhooks []helm.WebhookYAML
// extractWebhooksFromGeneratedFiles parses the files generated by controller-gen under
// config/webhooks and created Mutating and Validating helper structures to
// generate the webhook manifest for the helm-chart
func (s *initScaffolder) extractWebhooksFromGeneratedFiles() (mutatingWebhooks []templateswebhooks.DataWebhook,
validatingWebhooks []templateswebhooks.DataWebhook, err error) {
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
return webhooks, nil
if _, err := os.Stat(manifestFile); os.IsNotExist(err) {
log.Printf("webhook manifests were not found at %s", manifestFile)
return nil, nil, 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, 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
if err := yaml.Unmarshal([]byte(doc), &webhookConfig); err != nil {
log.Errorf("Error unmarshalling webhook YAML: %v", err)
continue
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.DataWebhookRule `yaml:"rules"`
FailurePolicy string `yaml:"failurePolicy"`
SideEffects string `yaml:"sideEffects"`
AdmissionReviewVersions []string `yaml:"admissionReviewVersions"`
} `yaml:"webhooks"`
}

// Determine the webhook type (mutating or validating)
webhookType := "unknown"
if webhookConfig.Kind == "MutatingWebhookConfiguration" {
webhookType = "mutating"
} else if webhookConfig.Kind == "ValidatingWebhookConfiguration" {
webhookType = "validating"
if err := yaml.Unmarshal([]byte(doc), &webhookConfig); err != nil {
log.Errorf("fail to unmarshalling webhook YAML: %v", err)
continue
}

// 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{""}
for _, w := range webhookConfig.Webhooks {
for i := range w.Rules {
if len(w.Rules[i].APIGroups) == 0 {
w.Rules[i].APIGroups = []string{""}
}
}
webhooks = append(webhooks, helm.WebhookYAML{
Name: webhook.Name,
Type: webhookType,
Path: webhook.ClientConfig.Service.Path,
Rules: webhook.Rules,
FailurePolicy: webhook.FailurePolicy,
SideEffects: webhook.SideEffects,
AdmissionReviewVersions: webhook.AdmissionReviewVersions,
})
webhook := templateswebhooks.DataWebhook{
Name: w.Name,
ServiceName: fmt.Sprintf("%s-webhook-service", s.config.GetProjectName()),
Path: w.ClientConfig.Service.Path,
FailurePolicy: w.FailurePolicy,
SideEffects: w.SideEffects,
AdmissionReviewVersions: w.AdmissionReviewVersions,
Rules: w.Rules,
}

if webhookConfig.Kind == "MutatingWebhookConfiguration" {
mutatingWebhooks = append(mutatingWebhooks, webhook)
} else if webhookConfig.Kind == "ValidatingWebhookConfiguration" {
validatingWebhooks = append(validatingWebhooks, webhook)
}
}
}
return webhooks

return mutatingWebhooks, validatingWebhooks, nil
}

// Helper function to copy files from config/ to dist/chart/templates/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ var _ machinery.Template = &WebhookService{}
// WebhookService scaffolds the Service for webhooks in the Helm chart
type WebhookService struct {
machinery.TemplateMixin
machinery.ProjectNameMixin

// Force if true allows overwriting the scaffolded file
Force bool
Expand All @@ -48,7 +49,7 @@ const webhookServiceTemplate = `{{` + "`" + `{{- if .Values.webhook.enable }}` +
apiVersion: v1
kind: Service
metadata:
name: {{ "{{ include \"chart.name\" . }}" }}-webhook-service
name: {{ .ProjectName }}-webhook-service
namespace: {{ "{{ .Release.Namespace }}" }}
labels:
{{ "{{- include \"chart.labels\" . | nindent 4 }}" }}
Expand Down
Loading

0 comments on commit 84f50b0

Please sign in to comment.