diff --git a/pkg/kube/podtemplatespec/podspec_template.go b/pkg/kube/podtemplatespec/podspec_template.go index f908a214a..9e0479210 100644 --- a/pkg/kube/podtemplatespec/podspec_template.go +++ b/pkg/kube/podtemplatespec/podspec_template.go @@ -93,13 +93,21 @@ func WithInitContainerByIndex(index int, funcs ...func(container *corev1.Contain } } -// WithPodLabels sets the PodTemplateSpec's Labels +// WithPodLabels merges the provided labels with existing PodTemplateSpec labels. +// This preserves labels added by external systems (like Kyverno policies) while +// allowing the operator to add or override its own labels. func WithPodLabels(labels map[string]string) Modification { if labels == nil { labels = map[string]string{} } return func(podTemplateSpec *corev1.PodTemplateSpec) { - podTemplateSpec.ObjectMeta.Labels = labels + if podTemplateSpec.ObjectMeta.Labels == nil { + podTemplateSpec.ObjectMeta.Labels = map[string]string{} + } + + for k, v := range labels { + podTemplateSpec.ObjectMeta.Labels[k] = v + } } } diff --git a/pkg/kube/podtemplatespec/podspec_template_test.go b/pkg/kube/podtemplatespec/podspec_template_test.go index 832c2821f..c419bf162 100644 --- a/pkg/kube/podtemplatespec/podspec_template_test.go +++ b/pkg/kube/podtemplatespec/podspec_template_test.go @@ -615,3 +615,63 @@ func getCustomContainer() corev1.Container { Image: "image-1", } } + +func TestWithPodLabels_MergeWithExistingLabels(t *testing.T) { + existingPodTemplate := &corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "foo.bar/customer": "acme-corp", + "foo.bar/env": "prod", + "external-label": "preserve-me", + }, + }, + } + + operatorLabels := map[string]string{ + "app": "database", + "version": "6.0", + } + + modification := WithPodLabels(operatorLabels) + modification(existingPodTemplate) + + expectedLabels := map[string]string{ + "foo.bar/customer": "acme-corp", // Preserved from existing + "foo.bar/env": "prod", // Preserved from existing + "external-label": "preserve-me", // Preserved from existing + "app": "database", // Added by operator + "version": "6.0", // Added by operator + } + + assert.Equal(t, expectedLabels, existingPodTemplate.ObjectMeta.Labels) +} + +func TestWithPodLabels_OverrideExistingLabels(t *testing.T) { + existingPodTemplate := &corev1.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + "app": "old-app", + "version": "5.0", + "external-label": "should-be-preserved", + }, + }, + } + + operatorLabels := map[string]string{ + "app": "database", // Should override existing + "version": "6.0", // Should override existing + "tier": "backend", // Should be added + } + + modification := WithPodLabels(operatorLabels) + modification(existingPodTemplate) + + expectedLabels := map[string]string{ + "external-label": "should-be-preserved", // Preserved + "app": "database", // Overridden by operator + "version": "6.0", // Overridden by operator + "tier": "backend", // Added by operator + } + + assert.Equal(t, expectedLabels, existingPodTemplate.ObjectMeta.Labels) +}