diff --git a/examples/operator/templates/mutating-webhook-configuration.yaml b/examples/operator/templates/mutating-webhook-configuration.yaml index a639bd8c..6dda4df5 100644 --- a/examples/operator/templates/mutating-webhook-configuration.yaml +++ b/examples/operator/templates/mutating-webhook-configuration.yaml @@ -16,6 +16,14 @@ webhooks: path: /mutate-ceph-example-com-v1-mycluster failurePolicy: Fail name: mmycluster.kb.io + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: + - namespace-1 + - '{{ .Release.Namespace }}' + - namespace-3 rules: - apiGroups: - test.example.com diff --git a/examples/operator/templates/validating-webhook-configuration.yaml b/examples/operator/templates/validating-webhook-configuration.yaml index 6710ba7e..e494f071 100644 --- a/examples/operator/templates/validating-webhook-configuration.yaml +++ b/examples/operator/templates/validating-webhook-configuration.yaml @@ -17,6 +17,14 @@ webhooks: path: /validate-ceph-example-com-v1alpha1-volume failurePolicy: Fail name: vvolume.kb.io + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: + - namespace-1 + - '{{ .Release.Namespace }}' + - namespace-3 rules: - apiGroups: - test.example.com diff --git a/pkg/processor/webhook/mutating.go b/pkg/processor/webhook/mutating.go index 465dec8a..e92c0282 100644 --- a/pkg/processor/webhook/mutating.go +++ b/pkg/processor/webhook/mutating.go @@ -8,6 +8,7 @@ import ( "github.com/arttor/helmify/pkg/helmify" v1 "k8s.io/api/admissionregistration/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -55,6 +56,7 @@ func (w mwh) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured for i, whc := range whConf.Webhooks { whc.ClientConfig.Service.Name = appMeta.TemplatedName(whc.ClientConfig.Service.Name) whc.ClientConfig.Service.Namespace = strings.ReplaceAll(whc.ClientConfig.Service.Namespace, appMeta.Namespace(), `{{ .Release.Namespace }}`) + mutateNamespaceSelector(appMeta, whc.NamespaceSelector) whConf.Webhooks[i] = whc } webhooks, _ := yaml.Marshal(whConf.Webhooks) @@ -98,3 +100,26 @@ func (r *mwhResult) Write(writer io.Writer) error { _, err := writer.Write(r.data) return err } + +const ( + nameLabel = "kubernetes.io/metadata.name" + namespaceTemplate = "{{ .Release.Namespace }}" +) + +// Replace the relase namespace in a namespace selector +func mutateNamespaceSelector(appMeta helmify.AppMetadata, sel *metav1.LabelSelector) { + if appMeta.Config().PreserveNs || sel == nil { + return + } + origNamespace := appMeta.Namespace() + for i, me := range sel.MatchExpressions { + if me.Key == nameLabel { + for vi, v := range me.Values { + if v == origNamespace { + me.Values[vi] = namespaceTemplate + } + } + sel.MatchExpressions[i] = me + } + } +} diff --git a/pkg/processor/webhook/mutating_test.go b/pkg/processor/webhook/mutating_test.go index cd389218..b24e35c5 100644 --- a/pkg/processor/webhook/mutating_test.go +++ b/pkg/processor/webhook/mutating_test.go @@ -3,6 +3,8 @@ package webhook import ( "testing" + "github.com/arttor/helmify/pkg/config" + "github.com/arttor/helmify/pkg/helmify" "github.com/arttor/helmify/pkg/metadata" "github.com/arttor/helmify/internal" @@ -26,6 +28,14 @@ webhooks: path: /mutate-ceph-example-com-v1alpha1-volume failurePolicy: Fail name: vvolume.kb.io + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: + - namespace-1 + - my-operator-system + - namespace-3 rules: - apiGroups: - test.example.com @@ -43,7 +53,7 @@ func Test_mwh_Process(t *testing.T) { t.Run("processed", func(t *testing.T) { obj := internal.GenerateObj(mwhYaml) - processed, _, err := testInstance.Process(&metadata.Service{}, obj) + processed, _, err := testInstance.Process(testAppMetaWithNamespace(), obj) assert.NoError(t, err) assert.Equal(t, true, processed) }) @@ -54,3 +64,14 @@ func Test_mwh_Process(t *testing.T) { assert.Equal(t, false, processed) }) } + +func testAppMetaWithNamespace() helmify.AppMetadata { + // Create an empty meta Service and load a dummy namespaced object. + am := metadata.New(config.Config{}) + am.Load(internal.GenerateObj(`apiVersion: v1 +kind: Service +metadata: + name: my-operator-controller-manager-metrics-service + namespace: my-operator-system`)) + return am +} diff --git a/pkg/processor/webhook/validating.go b/pkg/processor/webhook/validating.go index f9ca207a..54009cc3 100644 --- a/pkg/processor/webhook/validating.go +++ b/pkg/processor/webhook/validating.go @@ -55,6 +55,7 @@ func (w vwh) Process(appMeta helmify.AppMetadata, obj *unstructured.Unstructured for i, whc := range whConf.Webhooks { whc.ClientConfig.Service.Name = appMeta.TemplatedName(whc.ClientConfig.Service.Name) whc.ClientConfig.Service.Namespace = strings.ReplaceAll(whc.ClientConfig.Service.Namespace, appMeta.Namespace(), `{{ .Release.Namespace }}`) + mutateNamespaceSelector(appMeta, whc.NamespaceSelector) whConf.Webhooks[i] = whc } webhooks, _ := yaml.Marshal(whConf.Webhooks) diff --git a/pkg/processor/webhook/validating_test.go b/pkg/processor/webhook/validating_test.go index bb64a07a..f9740177 100644 --- a/pkg/processor/webhook/validating_test.go +++ b/pkg/processor/webhook/validating_test.go @@ -26,6 +26,14 @@ webhooks: path: /validate-ceph-example-com-v1alpha1-volume failurePolicy: Fail name: vvolume.kb.io + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: + - namespace-1 + - my-operator-system + - namespace-3 rules: - apiGroups: - test.example.com @@ -43,7 +51,7 @@ func Test_vwh_Process(t *testing.T) { t.Run("processed", func(t *testing.T) { obj := internal.GenerateObj(vwhYaml) - processed, _, err := testInstance.Process(&metadata.Service{}, obj) + processed, _, err := testInstance.Process(testAppMetaWithNamespace(), obj) assert.NoError(t, err) assert.Equal(t, true, processed) }) diff --git a/test_data/k8s-operator-kustomize.output b/test_data/k8s-operator-kustomize.output index 11e0d3ce..3a8ce6c6 100644 --- a/test_data/k8s-operator-kustomize.output +++ b/test_data/k8s-operator-kustomize.output @@ -748,6 +748,14 @@ webhooks: path: /validate-ceph-example-com-v1alpha1-volume failurePolicy: Fail name: vvolume.kb.io + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: + - namespace-1 + - my-operator-system + - namespace-3 rules: - apiGroups: - test.example.com @@ -835,6 +843,14 @@ webhooks: path: /mutate-ceph-example-com-v1-mycluster failurePolicy: Fail name: mmycluster.kb.io + namespaceSelector: + matchExpressions: + - key: kubernetes.io/metadata.name + operator: NotIn + values: + - namespace-1 + - my-operator-system + - namespace-3 rules: - apiGroups: - test.example.com