diff --git a/docs/book/src/cronjob-tutorial/testdata/project/dist/chart/templates/prometheus/controller-manager-metrics-monitor.yaml b/docs/book/src/cronjob-tutorial/testdata/project/dist/chart/templates/prometheus/controller-manager-metrics-monitor.yaml index a31654193d4..c8e2b22c26e 100644 --- a/docs/book/src/cronjob-tutorial/testdata/project/dist/chart/templates/prometheus/controller-manager-metrics-monitor.yaml +++ b/docs/book/src/cronjob-tutorial/testdata/project/dist/chart/templates/prometheus/controller-manager-metrics-monitor.yaml @@ -6,7 +6,7 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/name: project control-plane: controller-manager - name: {{ include "chart.name" . }}-controller-manager-metrics-monitor + name: project-controller-manager-metrics-monitor namespace: {{ .Release.Namespace }} spec: endpoints: diff --git a/docs/book/src/multiversion-tutorial/testdata/project/dist/chart/templates/prometheus/controller-manager-metrics-monitor.yaml b/docs/book/src/multiversion-tutorial/testdata/project/dist/chart/templates/prometheus/controller-manager-metrics-monitor.yaml index a31654193d4..c8e2b22c26e 100644 --- a/docs/book/src/multiversion-tutorial/testdata/project/dist/chart/templates/prometheus/controller-manager-metrics-monitor.yaml +++ b/docs/book/src/multiversion-tutorial/testdata/project/dist/chart/templates/prometheus/controller-manager-metrics-monitor.yaml @@ -6,7 +6,7 @@ metadata: app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/name: project control-plane: controller-manager - name: {{ include "chart.name" . }}-controller-manager-metrics-monitor + name: project-controller-manager-metrics-monitor namespace: {{ .Release.Namespace }} spec: endpoints: diff --git a/pkg/plugins/optional/helm/v2alpha/scaffolds/edit_kustomize.go b/pkg/plugins/optional/helm/v2alpha/scaffolds/edit_kustomize.go index 24c3537aa84..aaea41be648 100644 --- a/pkg/plugins/optional/helm/v2alpha/scaffolds/edit_kustomize.go +++ b/pkg/plugins/optional/helm/v2alpha/scaffolds/edit_kustomize.go @@ -109,6 +109,7 @@ func (s *editKustomizeScaffolder) Scaffold() error { slog.Warn("failed to remove stale generic ServiceMonitor", "path", staleSM, "error", rmErr) } } + namePrefix := resources.EstimatePrefix(s.config.GetProjectName()) chartConverter := kustomize.NewChartConverter(resources, s.config.GetProjectName(), s.outputDir) deploymentConfig := chartConverter.ExtractDeploymentConfig() @@ -119,7 +120,8 @@ func (s *editKustomizeScaffolder) Scaffold() error { chartFiles := []machinery.Builder{ &github.HelmChartCI{}, // GitHub Actions workflow for chart testing &templates.HelmChart{OutputDir: s.outputDir}, // Chart.yaml metadata - &templates.HelmValuesBasic{ // values.yaml with dynamic config + &templates.HelmValuesBasic{ + // values.yaml with dynamic config HasWebhooks: hasWebhooks, HasMetrics: hasMetrics, DeploymentConfig: deploymentConfig, @@ -134,7 +136,20 @@ func (s *editKustomizeScaffolder) Scaffold() error { // provide one via kustomize (../prometheus). This avoids duplicate objects // with the same name within the Helm chart. if !hasPrometheus { - chartFiles = append(chartFiles, &charttemplates.ServiceMonitor{OutputDir: s.outputDir}) + // Find the metrics service name from parsed resources + metricsServiceName := namePrefix + "-controller-manager-metrics-service" + for _, svc := range resources.Services { + if strings.Contains(svc.GetName(), "metrics-service") { + metricsServiceName = svc.GetName() + break + } + } + + chartFiles = append(chartFiles, &charttemplates.ServiceMonitor{ + OutputDir: s.outputDir, + NamePrefix: namePrefix, + ServiceName: metricsServiceName, + }) } // Generate template files from kustomize output diff --git a/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/chart_writer.go b/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/chart_writer.go index 6ed109e9da9..6fd3366026b 100644 --- a/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/chart_writer.go +++ b/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/chart_writer.go @@ -44,7 +44,8 @@ func NewChartWriter(templater *HelmTemplater, outputDir string) *ChartWriter { } // WriteResourceGroup writes a group of resources to a Helm template file -func (w *ChartWriter) WriteResourceGroup(fs machinery.Filesystem, groupName string, +func (w *ChartWriter) WriteResourceGroup( + fs machinery.Filesystem, groupName string, resources []*unstructured.Unstructured, ) error { // Special handling for namespace - write as single file @@ -73,7 +74,8 @@ func (w *ChartWriter) writeNamespaceFile(fs machinery.Filesystem, namespace *uns } // writeGroupDirectory writes resources as files in a group-specific directory -func (w *ChartWriter) writeGroupDirectory(fs machinery.Filesystem, groupName string, +func (w *ChartWriter) writeGroupDirectory( + fs machinery.Filesystem, groupName string, resources []*unstructured.Unstructured, ) error { var finalContent bytes.Buffer @@ -112,7 +114,8 @@ func (w *ChartWriter) shouldSplitFiles(groupName string) bool { } // writeSplitFiles writes each resource in the group to its own file -func (w *ChartWriter) writeSplitFiles(fs machinery.Filesystem, groupName string, +func (w *ChartWriter) writeSplitFiles( + fs machinery.Filesystem, groupName string, resources []*unstructured.Unstructured, ) error { // Create the group directory diff --git a/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/helm_templater.go b/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/helm_templater.go index d32ce64523b..ec8e96b3927 100644 --- a/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/helm_templater.go +++ b/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/helm_templater.go @@ -68,9 +68,6 @@ func (t *HelmTemplater) ApplyHelmSubstitutions(yamlContent string, resource *uns // Apply namespace substitutions yamlContent = t.substituteNamespace(yamlContent, resource) - // Template ServiceMonitor metadata.name to be chart.name-scoped for consistency - yamlContent = t.templateServiceMonitorNames(yamlContent, resource) - // Apply cert-manager and webhook-specific templating AFTER other substitutions yamlContent = t.substituteCertManagerReferences(yamlContent, resource) @@ -159,47 +156,6 @@ func (t *HelmTemplater) substituteCertManagerReferences(yamlContent string, _ *u return yamlContent } -// templateServiceNames ensures Service metadata.name uses Helm helpers for release-scoped naming. -// It converts hardcoded names like "-webhook-service" or -// "-controller-manager-metrics-service" to: -// -// name: {{ include "chart.serviceName" (dict "suffix" "" "context" .) }} -// NOTE: Service names are intentionally left as project-scoped (no release prefix) -// to match existing samples and e2e tests that refer to fixed service names. - -// templateServiceMonitorNames ensures ServiceMonitor metadata.name uses chart.name-based naming for consistency -// with existing tests and samples. It converts names like "controller-manager-metrics-monitor" or -// "-controller-manager-metrics-monitor" to: -// -// name: {{ include "chart.name" . }}-controller-manager-metrics-monitor -func (t *HelmTemplater) templateServiceMonitorNames(yamlContent string, resource *unstructured.Unstructured) string { - if resource.GetKind() != kindServiceMonitor { - return yamlContent - } - - origName := resource.GetName() - if origName == "" { - return yamlContent - } - - // Normalize suffix by stripping the project prefix if present - suffix := origName - prefix := t.projectName + "-" - if strings.HasPrefix(origName, prefix) { - suffix = strings.TrimPrefix(origName, prefix) - } - - // Only template if the intended target follows the conventional suffix - // This keeps any custom user-provided names intact - // For default scaffolding, suffix is typically "controller-manager-metrics-monitor" - templated := "{{ include \"chart.name\" . }}-" + suffix - - nameRe := regexp.MustCompile("(?m)^([\t ]*)name:\\s*" + regexp.QuoteMeta(origName) + "\\s*$") - yamlContent = nameRe.ReplaceAllString(yamlContent, "${1}name: "+templated) - - return yamlContent -} - // addHelmLabelsAndAnnotations replaces kustomize managed-by labels with Helm equivalents func (t *HelmTemplater) addHelmLabelsAndAnnotations(yamlContent string, _ *unstructured.Unstructured) string { // Replace app.kubernetes.io/managed-by: kustomize with Helm template diff --git a/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/helm_templater_test.go b/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/helm_templater_test.go index ca66eb15682..2365096a17d 100644 --- a/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/helm_templater_test.go +++ b/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/helm_templater_test.go @@ -389,6 +389,23 @@ metadata: Expect(result).To(ContainSubstring("name: test-project-controller-manager")) Expect(result).NotTo(ContainSubstring("{{ include")) }) + It("should preserve name for ServiceMonitor", func() { + serviceMonitorResource := &unstructured.Unstructured{} + serviceMonitorResource.SetAPIVersion("monitoring.coreos.com/v1") + serviceMonitorResource.SetKind("ServiceMonitor") + serviceMonitorResource.SetName("test-project-controller-manager-metrics-monitor") + + content := `apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: test-project-controller-manager-metrics-monitor` + + result := templater.ApplyHelmSubstitutions(content, serviceMonitorResource) + + // Name should remain unchanged + Expect(result).To(ContainSubstring("name: test-project-controller-manager-metrics-monitor")) + Expect(result).NotTo(ContainSubstring("{{ include")) + }) }) Context("edge cases", func() { diff --git a/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/parser.go b/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/parser.go index 488ad64e007..cda2c5070bf 100644 --- a/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/parser.go +++ b/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/parser.go @@ -20,6 +20,7 @@ import ( "fmt" "io" "os" + "strings" "gopkg.in/yaml.v3" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -151,3 +152,26 @@ func (p *Parser) categorizeResource(obj *unstructured.Unstructured, resources *P resources.Other = append(resources.Other, obj) } } + +func (pr *ParsedResources) EstimatePrefix(projectName string) string { + prefix := projectName + if pr.Deployment != nil { + if name := pr.Deployment.GetName(); name != "" { + deploymentPrefix, found := strings.CutSuffix(name, "-controller-manager") + if found { + prefix = deploymentPrefix + } + } + } + // Double check that the prefix is also the prefix for the service names + for _, svc := range pr.Services { + if name := svc.GetName(); name != "" { + if !strings.HasPrefix(name, prefix) { + // If not, fallback to just project name + prefix = projectName + break + } + } + } + return prefix +} diff --git a/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/parser_test.go b/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/parser_test.go index 237adc15495..0a9b216d829 100644 --- a/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/parser_test.go +++ b/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/kustomize/parser_test.go @@ -283,4 +283,42 @@ spec: Expect(issuer.GetKind()).To(Equal("Issuer")) }) }) + + Context("with custom prefix", func() { + BeforeEach(func() { + yamlContent := `--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ln-controller-manager + namespace: long-name-test-system +spec: + replicas: 1 +--- +apiVersion: v1 +kind: Service +metadata: + name: ln-controller-manager-metrics-service + namespace: long-name-test-system +spec: + ports: + - name: https + port: 8443 + targetPort: 8443 + selector: + control-plane: ln-controller-manager +` + err := os.WriteFile(tempFile, []byte(yamlContent), 0o600) + Expect(err).NotTo(HaveOccurred()) + + parser = NewParser(tempFile) + }) + + It("should use the correct prefix", func() { + resources, err := parser.Parse() + Expect(err).NotTo(HaveOccurred()) + + Expect(resources.EstimatePrefix("long-name")).To(Equal("ln")) + }) + }) }) diff --git a/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/templates/chart-templates/servicemonitor.go b/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/templates/chart-templates/servicemonitor.go index 55e82a0e36a..b74b2a410ed 100644 --- a/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/templates/chart-templates/servicemonitor.go +++ b/pkg/plugins/optional/helm/v2alpha/scaffolds/internal/templates/chart-templates/servicemonitor.go @@ -29,7 +29,12 @@ var _ machinery.Template = &ServiceMonitor{} // ServiceMonitor scaffolds a ServiceMonitor for Prometheus monitoring in the Helm chart type ServiceMonitor struct { machinery.TemplateMixin - machinery.ProjectNameMixin + + // Prefix + NamePrefix string + + // ServiceName is the full name of the metrics service, derived from Kustomize + ServiceName string // OutputDir specifies the output directory for the chart OutputDir string @@ -59,7 +64,7 @@ metadata: labels: {{ "{{- include \"chart.labels\" . | nindent 4 }}" }} control-plane: controller-manager - name: {{ .ProjectName }}-controller-manager-metrics-monitor + name: {{ .NamePrefix }}-controller-manager-metrics-monitor namespace: {{ "{{ .Release.Namespace }}" }} spec: endpoints: @@ -69,7 +74,7 @@ spec: bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token tlsConfig: {{ "{{- if .Values.certManager.enable }}" }} - serverName: {{ .ProjectName }}-controller-manager-metrics-service.{{ "{{ .Release.Namespace }}" }}.svc + serverName: {{ .ServiceName }}.{{ "{{ .Release.Namespace }}" }}.svc # Apply secure TLS configuration with cert-manager insecureSkipVerify: false ca: