Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 64 additions & 75 deletions pkg/plugins/optional/helm/v1alpha/scaffolds/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ 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"
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"
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,12 +80,12 @@ 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,
},
Expand All @@ -97,16 +94,21 @@ func (s *initScaffolder) Scaffold() error {
&manager.Deployment{
Force: s.force,
DeployImages: len(imagesEnvVars) > 0,
HasWebhooks: len(webhooks) > 0,
HasWebhooks: hasWebhooks,
},
&templatescertmanager.Certificate{},
&templatesmetrics.Service{},
&prometheus.Monitor{},
}

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

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 = &Service{}
// Service scaffolds the Service for webhooks in the Helm chart
type Service 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
Loading