From 29b10dd8872a8149646b99c2ee170795e7d7e40e Mon Sep 17 00:00:00 2001 From: Johannes Aubart Date: Mon, 19 May 2025 11:18:54 +0200 Subject: [PATCH 1/3] expand metadata mutator for finalizers and owner references --- docs/libs/resource.md | 13 +++-- pkg/resources/clusterrole.go | 8 +-- pkg/resources/clusterrolebinding.go | 8 +-- pkg/resources/configmap.go | 7 ++- pkg/resources/crd.go | 8 +-- pkg/resources/metadata.go | 81 ++++++++++++++++++++++++++--- pkg/resources/mutator.go | 1 + pkg/resources/namespace.go | 8 +-- pkg/resources/role.go | 8 +-- pkg/resources/rolebinding.go | 8 +-- pkg/resources/secret.go | 50 +++++++++++++----- pkg/resources/secret_test.go | 37 +++++++++++-- pkg/resources/serviceaccount.go | 8 +-- 13 files changed, 196 insertions(+), 49 deletions(-) diff --git a/docs/libs/resource.md b/docs/libs/resource.md index c613a72..9ac0ebe 100644 --- a/docs/libs/resource.md +++ b/docs/libs/resource.md @@ -9,12 +9,15 @@ Create or update a `ConfigMap`, a `ServiceAccount` and a `Deployment` using the ```go type myDeploymentMutator struct { + meta MetadataMutator } var _ resource.Mutator[*appsv1.Deployment] = &myDeploymentMutator{} -func newDeploymentMutator() resources.Mutator[*appsv1.Deployment] { - return &MyDeploymentMutator{} +func newDeploymentMutator(labels map[string]string, annotations map[string]string) resource.Mutator[*appsv1.Deployment] { + return &MyDeploymentMutator{ + meta: NewMetadataMutator(labels, annotations) + } } func (m *MyDeploymentMutator) String() string { @@ -38,7 +41,11 @@ func (m *MyDeploymentMutator) Mutate(deployment *appsv1.Deployment) error { Image: "test-image:latest", }, } - return nil + return m.meta.Mutate(deployment) +} + +func (m *MyDeploymentMutator) MetadataMutator() MetadataMutator { + return m.meta } diff --git a/pkg/resources/clusterrole.go b/pkg/resources/clusterrole.go index d67dbbf..2f55094 100644 --- a/pkg/resources/clusterrole.go +++ b/pkg/resources/clusterrole.go @@ -3,8 +3,6 @@ package resources import ( "fmt" - "sigs.k8s.io/controller-runtime/pkg/client" - v1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -12,7 +10,7 @@ import ( type ClusterRoleMutator struct { Name string Rules []v1.PolicyRule - meta Mutator[client.Object] + meta MetadataMutator } var _ Mutator[*v1.ClusterRole] = &ClusterRoleMutator{} @@ -45,3 +43,7 @@ func (m *ClusterRoleMutator) Mutate(r *v1.ClusterRole) error { r.Rules = m.Rules return m.meta.Mutate(r) } + +func (m *ClusterRoleMutator) MetadataMutator() MetadataMutator { + return m.meta +} diff --git a/pkg/resources/clusterrolebinding.go b/pkg/resources/clusterrolebinding.go index 36daf2b..e222a2f 100644 --- a/pkg/resources/clusterrolebinding.go +++ b/pkg/resources/clusterrolebinding.go @@ -3,8 +3,6 @@ package resources import ( "fmt" - "sigs.k8s.io/controller-runtime/pkg/client" - v1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -13,7 +11,7 @@ type ClusterRoleBindingMutator struct { ClusterRoleBindingName string RoleRef v1.RoleRef Subjects []v1.Subject - meta Mutator[client.Object] + meta MetadataMutator } var _ Mutator[*v1.ClusterRoleBinding] = &ClusterRoleBindingMutator{} @@ -48,3 +46,7 @@ func (m *ClusterRoleBindingMutator) Mutate(r *v1.ClusterRoleBinding) error { r.Subjects = m.Subjects return m.meta.Mutate(r) } + +func (m *ClusterRoleBindingMutator) MetadataMutator() MetadataMutator { + return m.meta +} diff --git a/pkg/resources/configmap.go b/pkg/resources/configmap.go index baea795..a8c9945 100644 --- a/pkg/resources/configmap.go +++ b/pkg/resources/configmap.go @@ -5,14 +5,13 @@ import ( core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" ) type ConfigMapMutator struct { Name string Namespace string Data map[string]string - meta Mutator[client.Object] + meta MetadataMutator } var _ Mutator[*core.ConfigMap] = &ConfigMapMutator{} @@ -53,3 +52,7 @@ func (m *ConfigMapMutator) Mutate(cm *core.ConfigMap) error { } return m.meta.Mutate(cm) } + +func (m *ConfigMapMutator) MetadataMutator() MetadataMutator { + return m.meta +} diff --git a/pkg/resources/crd.go b/pkg/resources/crd.go index 5fcabd2..35ebe78 100644 --- a/pkg/resources/crd.go +++ b/pkg/resources/crd.go @@ -3,15 +3,13 @@ package resources import ( "fmt" - "sigs.k8s.io/controller-runtime/pkg/client" - apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) type crdMutator struct { crd *apiextv1.CustomResourceDefinition - meta Mutator[client.Object] + meta MetadataMutator } var _ Mutator[*apiextv1.CustomResourceDefinition] = &crdMutator{} @@ -40,3 +38,7 @@ func (m *crdMutator) Mutate(r *apiextv1.CustomResourceDefinition) error { m.crd.Spec.DeepCopyInto(&r.Spec) return m.meta.Mutate(r) } + +func (m *crdMutator) MetadataMutator() MetadataMutator { + return m.meta +} diff --git a/pkg/resources/metadata.go b/pkg/resources/metadata.go index 2c6c7d5..6714a37 100644 --- a/pkg/resources/metadata.go +++ b/pkg/resources/metadata.go @@ -1,23 +1,45 @@ package resources import ( + "maps" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) type metadataMutator struct { - Labels map[string]string - Annotations map[string]string + Labels map[string]string + Annotations map[string]string + OwnerReferences []metav1.OwnerReference + Finalizers []string +} + +type MetadataMutator interface { + Mutator[client.Object] + WithOwnerReferences(ownerReferences []metav1.OwnerReference) MetadataMutator + WithFinalizers(finalizers []string) MetadataMutator } var _ Mutator[client.Object] = &metadataMutator{} +var _ MetadataMutator = &metadataMutator{} -func NewMetadataMutator(labels map[string]string, annotations map[string]string) Mutator[client.Object] { +func NewMetadataMutator(labels map[string]string, annotations map[string]string) MetadataMutator { return &metadataMutator{ Labels: labels, Annotations: annotations, } } +func (m *metadataMutator) WithOwnerReferences(ownerReferences []metav1.OwnerReference) MetadataMutator { + m.OwnerReferences = ownerReferences + return m +} + +func (m *metadataMutator) WithFinalizers(finalizers []string) MetadataMutator { + m.Finalizers = finalizers + return m +} + func (m *metadataMutator) String() string { return "metadata" } @@ -30,20 +52,63 @@ func (m *metadataMutator) Mutate(res client.Object) error { if m.Labels != nil { if res.GetLabels() == nil { res.SetLabels(make(map[string]string)) - } - for k, v := range m.Labels { - res.GetLabels()[k] = v + maps.Copy(res.GetLabels(), m.Labels) } } if m.Annotations != nil { if res.GetAnnotations() == nil { res.SetAnnotations(make(map[string]string)) + maps.Copy(res.GetAnnotations(), m.Annotations) } + } + + if m.OwnerReferences != nil { + // ensure that all owner references in m are also in res + if len(res.GetOwnerReferences()) == 0 { + res.SetOwnerReferences(make([]metav1.OwnerReference, len(m.OwnerReferences))) + for i, ownerRef := range m.OwnerReferences { + res.GetOwnerReferences()[i] = *ownerRef.DeepCopy() + } + } else { + for _, ownerRef := range m.OwnerReferences { + found := false + for _, existingRef := range res.GetOwnerReferences() { + if ownerRef.UID == existingRef.UID { + found = true + break + } + } + if !found { + res.SetOwnerReferences(append(res.GetOwnerReferences(), *ownerRef.DeepCopy())) + } + } + } + } - for k, v := range m.Annotations { - res.GetAnnotations()[k] = v + if m.Finalizers != nil { + if len(res.GetFinalizers()) == 0 { + res.SetFinalizers(make([]string, len(m.Finalizers))) + copy(res.GetFinalizers(), m.Finalizers) + } else { + for _, fin := range m.Finalizers { + found := false + for _, existingFin := range res.GetFinalizers() { + if fin == existingFin { + found = true + break + } + } + if !found { + res.SetFinalizers(append(res.GetFinalizers(), fin)) + } + } } } + return nil } + +func (m *metadataMutator) MetadataMutator() MetadataMutator { + return m +} diff --git a/pkg/resources/mutator.go b/pkg/resources/mutator.go index 7aeb3ce..c6bee99 100644 --- a/pkg/resources/mutator.go +++ b/pkg/resources/mutator.go @@ -12,6 +12,7 @@ type Mutator[K client.Object] interface { Empty() K Mutate(res K) error String() string + MetadataMutator() MetadataMutator } func GetResource[K client.Object](ctx context.Context, clt client.Client, m Mutator[K]) (K, error) { diff --git a/pkg/resources/namespace.go b/pkg/resources/namespace.go index 23a0c24..a6023c4 100644 --- a/pkg/resources/namespace.go +++ b/pkg/resources/namespace.go @@ -3,15 +3,13 @@ package resources import ( "fmt" - "sigs.k8s.io/controller-runtime/pkg/client" - v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) type namespaceMutator struct { name string - meta Mutator[client.Object] + meta MetadataMutator } var _ Mutator[*v1.Namespace] = &namespaceMutator{} @@ -39,3 +37,7 @@ func (m *namespaceMutator) Empty() *v1.Namespace { func (m *namespaceMutator) Mutate(r *v1.Namespace) error { return m.meta.Mutate(r) } + +func (m *namespaceMutator) MetadataMutator() MetadataMutator { + return m.meta +} diff --git a/pkg/resources/role.go b/pkg/resources/role.go index 30ae583..cbd1f2c 100644 --- a/pkg/resources/role.go +++ b/pkg/resources/role.go @@ -3,8 +3,6 @@ package resources import ( "fmt" - "sigs.k8s.io/controller-runtime/pkg/client" - v1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -13,7 +11,7 @@ type RoleMutator struct { Name string Namespace string Rules []v1.PolicyRule - meta Mutator[client.Object] + meta MetadataMutator } var _ Mutator[*v1.Role] = &RoleMutator{} @@ -48,3 +46,7 @@ func (m *RoleMutator) Mutate(r *v1.Role) error { r.Rules = m.Rules return m.meta.Mutate(r) } + +func (m *RoleMutator) MetadataMutator() MetadataMutator { + return m.meta +} diff --git a/pkg/resources/rolebinding.go b/pkg/resources/rolebinding.go index a6b4f86..00f26af 100644 --- a/pkg/resources/rolebinding.go +++ b/pkg/resources/rolebinding.go @@ -3,8 +3,6 @@ package resources import ( "fmt" - "sigs.k8s.io/controller-runtime/pkg/client" - v1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -14,7 +12,7 @@ type RoleBindingMutator struct { Namespace string Subjects []v1.Subject RoleRef v1.RoleRef - meta Mutator[client.Object] + meta MetadataMutator } var _ Mutator[*v1.RoleBinding] = &RoleBindingMutator{} @@ -51,3 +49,7 @@ func (m *RoleBindingMutator) Mutate(rb *v1.RoleBinding) error { rb.RoleRef = m.RoleRef return m.meta.Mutate(rb) } + +func (m *RoleBindingMutator) MetadataMutator() MetadataMutator { + return m.meta +} diff --git a/pkg/resources/secret.go b/pkg/resources/secret.go index b6866c2..0b2f191 100644 --- a/pkg/resources/secret.go +++ b/pkg/resources/secret.go @@ -3,17 +3,19 @@ package resources import ( "fmt" + "maps" + core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" ) type SecretMutator struct { - Name string - Namespace string - Data map[string][]byte - Type core.SecretType - meta Mutator[client.Object] + Name string + Namespace string + Data map[string][]byte + StringData map[string]string + Type core.SecretType + meta MetadataMutator } var _ Mutator[*core.Secret] = &SecretMutator{} @@ -28,12 +30,22 @@ func NewSecretMutator(name, namespace string, data map[string][]byte, secretType } } +func NewSecretMutatorWithStringData(name, namespace string, stringData map[string]string, secretType core.SecretType, labels map[string]string, annotations map[string]string) Mutator[*core.Secret] { + return &SecretMutator{ + Name: name, + Namespace: namespace, + StringData: stringData, + Type: secretType, + meta: NewMetadataMutator(labels, annotations), + } +} + func (m *SecretMutator) String() string { return fmt.Sprintf("secret %s/%s", m.Namespace, m.Name) } func (m *SecretMutator) Empty() *core.Secret { - return &core.Secret{ + s := &core.Secret{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", Kind: "Secret", @@ -42,17 +54,31 @@ func (m *SecretMutator) Empty() *core.Secret { Name: m.Name, Namespace: m.Namespace, }, - Data: m.Data, Type: m.Type, } + if m.Data != nil { + s.Data = make(map[string][]byte, len(m.Data)) + maps.Copy(s.Data, m.Data) + } + if m.StringData != nil { + s.StringData = make(map[string]string, len(m.StringData)) + maps.Copy(s.StringData, m.StringData) + } + return s } func (m *SecretMutator) Mutate(s *core.Secret) error { - if s.Data == nil { - s.Data = make(map[string][]byte) + if m.Data != nil { + s.Data = make(map[string][]byte, len(m.Data)) + maps.Copy(s.Data, m.Data) } - for key, value := range m.Data { - s.Data[key] = value + if m.StringData != nil { + s.StringData = make(map[string]string, len(m.StringData)) + maps.Copy(s.StringData, m.StringData) } return m.meta.Mutate(s) } + +func (m *SecretMutator) MetadataMutator() MetadataMutator { + return m.meta +} diff --git a/pkg/resources/secret_test.go b/pkg/resources/secret_test.go index b351132..2fda4ff 100644 --- a/pkg/resources/secret_test.go +++ b/pkg/resources/secret_test.go @@ -19,6 +19,7 @@ var _ = Describe("SecretMutator", func() { fakeClient client.WithWatch scheme *runtime.Scheme data map[string][]byte + stringData map[string]string labels map[string]string annotations map[string]string secretType core.SecretType @@ -39,15 +40,14 @@ var _ = Describe("SecretMutator", func() { // Define data, labels, annotations, and secret type data = map[string][]byte{"key1": []byte("value1"), "key2": []byte("value2")} + stringData = map[string]string{"key3": "value3", "key4": "value4"} labels = map[string]string{"label1": "value1"} annotations = map[string]string{"annotation1": "value1"} secretType = core.SecretTypeOpaque - - // Create a Secret mutator - mutator = resources.NewSecretMutator("test-secret", "test-namespace", data, secretType, labels, annotations) }) It("should create an empty Secret with correct metadata", func() { + mutator = resources.NewSecretMutator("test-secret", "test-namespace", data, secretType, labels, annotations) secret := mutator.Empty() Expect(secret.Name).To(Equal("test-secret")) @@ -56,9 +56,24 @@ var _ = Describe("SecretMutator", func() { Expect(secret.Kind).To(Equal("Secret")) Expect(secret.Type).To(Equal(secretType)) Expect(secret.Data).To(Equal(data)) + Expect(secret.StringData).To(BeEmpty()) + }) + + It("should create an empty Secret with correct metadata (string data)", func() { + mutator = resources.NewSecretMutatorWithStringData("test-secret", "test-namespace", stringData, secretType, labels, annotations) + secret := mutator.Empty() + + Expect(secret.Name).To(Equal("test-secret")) + Expect(secret.Namespace).To(Equal("test-namespace")) + Expect(secret.APIVersion).To(Equal("v1")) + Expect(secret.Kind).To(Equal("Secret")) + Expect(secret.Type).To(Equal(secretType)) + Expect(secret.Data).To(BeEmpty()) + Expect(secret.StringData).To(Equal(stringData)) }) It("should apply data, labels, and annotations using Mutate", func() { + mutator = resources.NewSecretMutator("test-secret", "test-namespace", data, secretType, labels, annotations) secret := mutator.Empty() // Apply the mutator's Mutate method @@ -66,11 +81,27 @@ var _ = Describe("SecretMutator", func() { // Verify that the data, labels, and annotations are applied Expect(secret.Data).To(Equal(data)) + Expect(secret.StringData).To(BeEmpty()) + Expect(secret.Labels).To(Equal(labels)) + Expect(secret.Annotations).To(Equal(annotations)) + }) + + It("should apply data, labels, and annotations using Mutate (string data)", func() { + mutator = resources.NewSecretMutatorWithStringData("test-secret", "test-namespace", stringData, secretType, labels, annotations) + secret := mutator.Empty() + + // Apply the mutator's Mutate method + Expect(mutator.Mutate(secret)).To(Succeed()) + + // Verify that the data, labels, and annotations are applied + Expect(secret.Data).To(BeEmpty()) + Expect(secret.StringData).To(Equal(stringData)) Expect(secret.Labels).To(Equal(labels)) Expect(secret.Annotations).To(Equal(annotations)) }) It("should create and retrieve the Secret using the fake client", func() { + mutator = resources.NewSecretMutator("test-secret", "test-namespace", data, secretType, labels, annotations) secret := mutator.Empty() Expect(mutator.Mutate(secret)).To(Succeed()) diff --git a/pkg/resources/serviceaccount.go b/pkg/resources/serviceaccount.go index be14eb8..3d3d79c 100644 --- a/pkg/resources/serviceaccount.go +++ b/pkg/resources/serviceaccount.go @@ -3,8 +3,6 @@ package resources import ( "fmt" - "sigs.k8s.io/controller-runtime/pkg/client" - core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -12,7 +10,7 @@ import ( type ServiceAccountMutator struct { Name string Namespace string - meta Mutator[client.Object] + meta MetadataMutator } var _ Mutator[*core.ServiceAccount] = &ServiceAccountMutator{} @@ -45,3 +43,7 @@ func (m *ServiceAccountMutator) Empty() *core.ServiceAccount { func (m *ServiceAccountMutator) Mutate(s *core.ServiceAccount) error { return m.meta.Mutate(s) } + +func (m *ServiceAccountMutator) MetadataMutator() MetadataMutator { + return m.meta +} From 576b3da6bb6bf27116eb042ad8fd392936e2f43b Mon Sep 17 00:00:00 2001 From: Johannes Aubart Date: Tue, 20 May 2025 09:55:25 +0200 Subject: [PATCH 2/3] fix bug and add metadata mutator test --- pkg/resources/metadata.go | 4 +- pkg/resources/metadata_test.go | 74 ++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 pkg/resources/metadata_test.go diff --git a/pkg/resources/metadata.go b/pkg/resources/metadata.go index 6714a37..5e0293c 100644 --- a/pkg/resources/metadata.go +++ b/pkg/resources/metadata.go @@ -52,15 +52,15 @@ func (m *metadataMutator) Mutate(res client.Object) error { if m.Labels != nil { if res.GetLabels() == nil { res.SetLabels(make(map[string]string)) - maps.Copy(res.GetLabels(), m.Labels) } + maps.Copy(res.GetLabels(), m.Labels) } if m.Annotations != nil { if res.GetAnnotations() == nil { res.SetAnnotations(make(map[string]string)) - maps.Copy(res.GetAnnotations(), m.Annotations) } + maps.Copy(res.GetAnnotations(), m.Annotations) } if m.OwnerReferences != nil { diff --git a/pkg/resources/metadata_test.go b/pkg/resources/metadata_test.go new file mode 100644 index 0000000..cdc18fa --- /dev/null +++ b/pkg/resources/metadata_test.go @@ -0,0 +1,74 @@ +package resources_test + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + . "github.com/onsi/gomega/gstruct" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/openmcp-project/controller-utils/pkg/resources" +) + +var _ = Describe("Metadata Mutator", func() { + + It("should correctly add labels, annotations, owner references and finalizers", func() { + ns := &corev1.Namespace{} + ns.ObjectMeta = metav1.ObjectMeta{ + Name: "test-namespace", + Labels: map[string]string{ + "oldLabel": "old", + }, + Annotations: map[string]string{ + "oldAnnotation": "old", + }, + OwnerReferences: []metav1.OwnerReference{ + { + APIVersion: "v1", + Kind: "Owner", + Name: "owner", + UID: "12345", + }, + }, + Finalizers: []string{ + "oldFinalizer", + }, + } + + m := resources.NewMetadataMutator(map[string]string{"newLabel": "new"}, map[string]string{"newAnnotation": "new"}). + WithOwnerReferences([]metav1.OwnerReference{ + { + APIVersion: "v1", + Kind: "NewOwner", + Name: "newOwner", + UID: "67890", + }, + }). + WithFinalizers([]string{"newFinalizer"}) + Expect(m.Mutate(ns)).To(Succeed()) + Expect(ns.Labels).To(HaveKeyWithValue("oldLabel", "old")) + Expect(ns.Labels).To(HaveKeyWithValue("newLabel", "new")) + Expect(ns.Annotations).To(HaveKeyWithValue("oldAnnotation", "old")) + Expect(ns.Annotations).To(HaveKeyWithValue("newAnnotation", "new")) + Expect(ns.OwnerReferences).To(ConsistOf( + MatchFields(IgnoreExtras, Fields{ + "APIVersion": Equal("v1"), + "Kind": Equal("Owner"), + "Name": Equal("owner"), + "UID": BeEquivalentTo("12345"), + }), + MatchFields(IgnoreExtras, Fields{ + "APIVersion": Equal("v1"), + "Kind": Equal("NewOwner"), + "Name": Equal("newOwner"), + "UID": BeEquivalentTo("67890"), + }), + )) + Expect(ns.Finalizers).To(ConsistOf( + "oldFinalizer", + "newFinalizer", + )) + }) + +}) From 7220ac7630ea4de616ff31155c86237608ce7c96 Mon Sep 17 00:00:00 2001 From: Johannes Aubart Date: Tue, 20 May 2025 10:22:28 +0200 Subject: [PATCH 3/3] move labels and annotations in resource mutators into metadata mutator --- docs/libs/resource.md | 13 +++++++------ pkg/crds/crds.go | 4 +++- pkg/resources/clusterrole.go | 4 ++-- pkg/resources/clusterrole_test.go | 3 ++- pkg/resources/clusterrolebinding.go | 4 ++-- pkg/resources/clusterrolebinding_test.go | 3 ++- pkg/resources/configmap.go | 4 ++-- pkg/resources/configmap_test.go | 3 ++- pkg/resources/crd.go | 4 ++-- pkg/resources/crd_test.go | 3 ++- pkg/resources/metadata.go | 19 ++++++++++++++----- pkg/resources/metadata_test.go | 8 +++++++- pkg/resources/mutator_test.go | 3 ++- pkg/resources/namespace.go | 4 ++-- pkg/resources/namespace_test.go | 3 ++- pkg/resources/role.go | 4 ++-- pkg/resources/role_test.go | 3 ++- pkg/resources/rolebinding.go | 4 ++-- pkg/resources/rolebinding_test.go | 3 ++- pkg/resources/secret.go | 8 ++++---- pkg/resources/secret_test.go | 15 ++++++++++----- pkg/resources/serviceaccount.go | 4 ++-- pkg/resources/serviceaccount_test.go | 3 ++- 23 files changed, 79 insertions(+), 47 deletions(-) diff --git a/docs/libs/resource.md b/docs/libs/resource.md index 9ac0ebe..6fbe387 100644 --- a/docs/libs/resource.md +++ b/docs/libs/resource.md @@ -14,9 +14,9 @@ type myDeploymentMutator struct { var _ resource.Mutator[*appsv1.Deployment] = &myDeploymentMutator{} -func newDeploymentMutator(labels map[string]string, annotations map[string]string) resource.Mutator[*appsv1.Deployment] { +func newDeploymentMutator() resource.Mutator[*appsv1.Deployment] { return &MyDeploymentMutator{ - meta: NewMetadataMutator(labels, annotations) + meta: NewMetadataMutator() } } @@ -44,18 +44,19 @@ func (m *MyDeploymentMutator) Mutate(deployment *appsv1.Deployment) error { return m.meta.Mutate(deployment) } -func (m *MyDeploymentMutator) MetadataMutator() MetadataMutator { +func (m *MyDeploymentMutator) MetadataMutator() resource.MetadataMutator { return m.meta } func ReconcileResources(ctx context.Context, client client.Client) error { - configMapResource := resource.NewConfigMap("my-configmap", "my-namespace", map[string]string{ + configMapResource := resource.NewConfigMapMutator("my-configmap", "my-namespace") + configMapResource.MetadataMutator().WithLabels(map[string]string{ "label1": "value1", "label2": "value2", - }, nil) + }) - serviceAccountResource := resource.NewServiceAccount("my-serviceaccount", "my-namespace", nil, nil) + serviceAccountResource := resource.NewServiceAccountMutator("my-serviceaccount", "my-namespace") myDeploymentMutator := newDeploymentMutator() diff --git a/pkg/crds/crds.go b/pkg/crds/crds.go index 0372e97..cc7224d 100644 --- a/pkg/crds/crds.go +++ b/pkg/crds/crds.go @@ -57,7 +57,9 @@ func (m *CRDManager) CreateOrUpdateCRDs(ctx context.Context, log *logging.Logger if log != nil { log.Info("creating/updating CRD", "name", crd.Name, "cluster", c.ID()) } - err = resources.CreateOrUpdateResource(ctx, c.Client(), resources.NewCRDMutator(crd, crd.Labels, crd.Annotations)) + m := resources.NewCRDMutator(crd) + m.MetadataMutator().WithLabels(crd.Labels).WithAnnotations(crd.Annotations) + err = resources.CreateOrUpdateResource(ctx, c.Client(), m) errs = errors.Join(errs, err) } diff --git a/pkg/resources/clusterrole.go b/pkg/resources/clusterrole.go index 2f55094..3d55951 100644 --- a/pkg/resources/clusterrole.go +++ b/pkg/resources/clusterrole.go @@ -15,11 +15,11 @@ type ClusterRoleMutator struct { var _ Mutator[*v1.ClusterRole] = &ClusterRoleMutator{} -func NewClusterRoleMutator(name string, rules []v1.PolicyRule, labels map[string]string, annotations map[string]string) Mutator[*v1.ClusterRole] { +func NewClusterRoleMutator(name string, rules []v1.PolicyRule) Mutator[*v1.ClusterRole] { return &ClusterRoleMutator{ Name: name, Rules: rules, - meta: NewMetadataMutator(labels, annotations), + meta: NewMetadataMutator(), } } diff --git a/pkg/resources/clusterrole_test.go b/pkg/resources/clusterrole_test.go index 9e4efcf..d467e5a 100644 --- a/pkg/resources/clusterrole_test.go +++ b/pkg/resources/clusterrole_test.go @@ -48,7 +48,8 @@ var _ = Describe("ClusterRoleMutator", func() { annotations = map[string]string{"annotation1": "value1"} // Create a cluster role mutator - mutator = resources.NewClusterRoleMutator("test-clusterrole", rules, labels, annotations) + mutator = resources.NewClusterRoleMutator("test-clusterrole", rules) + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) }) It("should create an empty cluster role with correct metadata", func() { diff --git a/pkg/resources/clusterrolebinding.go b/pkg/resources/clusterrolebinding.go index e222a2f..7cda001 100644 --- a/pkg/resources/clusterrolebinding.go +++ b/pkg/resources/clusterrolebinding.go @@ -16,12 +16,12 @@ type ClusterRoleBindingMutator struct { var _ Mutator[*v1.ClusterRoleBinding] = &ClusterRoleBindingMutator{} -func NewClusterRoleBindingMutator(clusterRoleBindingName string, subjects []v1.Subject, roleRef v1.RoleRef, labels map[string]string, annotations map[string]string) Mutator[*v1.ClusterRoleBinding] { +func NewClusterRoleBindingMutator(clusterRoleBindingName string, subjects []v1.Subject, roleRef v1.RoleRef) Mutator[*v1.ClusterRoleBinding] { return &ClusterRoleBindingMutator{ ClusterRoleBindingName: clusterRoleBindingName, RoleRef: roleRef, Subjects: subjects, - meta: NewMetadataMutator(labels, annotations), + meta: NewMetadataMutator(), } } diff --git a/pkg/resources/clusterrolebinding_test.go b/pkg/resources/clusterrolebinding_test.go index 9f6b041..b639983 100644 --- a/pkg/resources/clusterrolebinding_test.go +++ b/pkg/resources/clusterrolebinding_test.go @@ -50,7 +50,8 @@ var _ = Describe("ClusterRoleBindingMutator", func() { annotations = map[string]string{"annotation1": "value1"} // Create a cluster role binding mutator - mutator = resources.NewClusterRoleBindingMutator("test-clusterrolebinding", subjects, roleRef, labels, annotations) + mutator = resources.NewClusterRoleBindingMutator("test-clusterrolebinding", subjects, roleRef) + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) }) It("should create an empty cluster role binding with correct metadata", func() { diff --git a/pkg/resources/configmap.go b/pkg/resources/configmap.go index a8c9945..a531ee5 100644 --- a/pkg/resources/configmap.go +++ b/pkg/resources/configmap.go @@ -16,12 +16,12 @@ type ConfigMapMutator struct { var _ Mutator[*core.ConfigMap] = &ConfigMapMutator{} -func NewConfigMapMutator(name, namespace string, data map[string]string, labels map[string]string, annotations map[string]string) Mutator[*core.ConfigMap] { +func NewConfigMapMutator(name, namespace string, data map[string]string) Mutator[*core.ConfigMap] { return &ConfigMapMutator{ Name: name, Namespace: namespace, Data: data, - meta: NewMetadataMutator(labels, annotations), + meta: NewMetadataMutator(), } } diff --git a/pkg/resources/configmap_test.go b/pkg/resources/configmap_test.go index 06ed8a3..04c49a8 100644 --- a/pkg/resources/configmap_test.go +++ b/pkg/resources/configmap_test.go @@ -42,7 +42,8 @@ var _ = Describe("ConfigMapMutator", func() { annotations = map[string]string{"annotation1": "value1"} // Create a ConfigMap mutator - mutator = resources.NewConfigMapMutator("test-configmap", "test-namespace", data, labels, annotations) + mutator = resources.NewConfigMapMutator("test-configmap", "test-namespace", data) + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) }) It("should create an empty ConfigMap with correct metadata", func() { diff --git a/pkg/resources/crd.go b/pkg/resources/crd.go index 35ebe78..84503cc 100644 --- a/pkg/resources/crd.go +++ b/pkg/resources/crd.go @@ -14,8 +14,8 @@ type crdMutator struct { var _ Mutator[*apiextv1.CustomResourceDefinition] = &crdMutator{} -func NewCRDMutator(crd *apiextv1.CustomResourceDefinition, labels map[string]string, annotations map[string]string) Mutator[*apiextv1.CustomResourceDefinition] { - return &crdMutator{crd: crd, meta: NewMetadataMutator(labels, annotations)} +func NewCRDMutator(crd *apiextv1.CustomResourceDefinition) Mutator[*apiextv1.CustomResourceDefinition] { + return &crdMutator{crd: crd, meta: NewMetadataMutator()} } func (m *crdMutator) String() string { diff --git a/pkg/resources/crd_test.go b/pkg/resources/crd_test.go index 7f86959..c69675f 100644 --- a/pkg/resources/crd_test.go +++ b/pkg/resources/crd_test.go @@ -61,7 +61,8 @@ var _ = Describe("CRDMutator", func() { } // Create a CRD mutator - mutator = resources.NewCRDMutator(crd, labels, annotations) + mutator = resources.NewCRDMutator(crd) + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) }) It("should create an empty CRD with correct metadata", func() { diff --git a/pkg/resources/metadata.go b/pkg/resources/metadata.go index 5e0293c..3209494 100644 --- a/pkg/resources/metadata.go +++ b/pkg/resources/metadata.go @@ -18,16 +18,25 @@ type MetadataMutator interface { Mutator[client.Object] WithOwnerReferences(ownerReferences []metav1.OwnerReference) MetadataMutator WithFinalizers(finalizers []string) MetadataMutator + WithLabels(labels map[string]string) MetadataMutator + WithAnnotations(annotations map[string]string) MetadataMutator } var _ Mutator[client.Object] = &metadataMutator{} var _ MetadataMutator = &metadataMutator{} -func NewMetadataMutator(labels map[string]string, annotations map[string]string) MetadataMutator { - return &metadataMutator{ - Labels: labels, - Annotations: annotations, - } +func NewMetadataMutator() MetadataMutator { + return &metadataMutator{} +} + +func (m *metadataMutator) WithLabels(labels map[string]string) MetadataMutator { + m.Labels = labels + return m +} + +func (m *metadataMutator) WithAnnotations(annotations map[string]string) MetadataMutator { + m.Annotations = annotations + return m } func (m *metadataMutator) WithOwnerReferences(ownerReferences []metav1.OwnerReference) MetadataMutator { diff --git a/pkg/resources/metadata_test.go b/pkg/resources/metadata_test.go index cdc18fa..3e06273 100644 --- a/pkg/resources/metadata_test.go +++ b/pkg/resources/metadata_test.go @@ -36,7 +36,13 @@ var _ = Describe("Metadata Mutator", func() { }, } - m := resources.NewMetadataMutator(map[string]string{"newLabel": "new"}, map[string]string{"newAnnotation": "new"}). + m := resources.NewMetadataMutator(). + WithLabels(map[string]string{ + "newLabel": "new", + }). + WithAnnotations(map[string]string{ + "newAnnotation": "new", + }). WithOwnerReferences([]metav1.OwnerReference{ { APIVersion: "v1", diff --git a/pkg/resources/mutator_test.go b/pkg/resources/mutator_test.go index 1d496d5..77a9691 100644 --- a/pkg/resources/mutator_test.go +++ b/pkg/resources/mutator_test.go @@ -42,7 +42,8 @@ var _ = Describe("Resource Functions", func() { data = map[string]string{"key1": "value1", "key2": "value2"} // Create a ConfigMap mutator - mutator = resources.NewConfigMapMutator("test-configmap", "test-namespace", data, labels, annotations) + mutator = resources.NewConfigMapMutator("test-configmap", "test-namespace", data) + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) }) It("should get, create or update, and delete a resource", func() { diff --git a/pkg/resources/namespace.go b/pkg/resources/namespace.go index a6023c4..eedc66c 100644 --- a/pkg/resources/namespace.go +++ b/pkg/resources/namespace.go @@ -14,8 +14,8 @@ type namespaceMutator struct { var _ Mutator[*v1.Namespace] = &namespaceMutator{} -func NewNamespaceMutator(name string, labels map[string]string, annotations map[string]string) Mutator[*v1.Namespace] { - return &namespaceMutator{name: name, meta: NewMetadataMutator(labels, annotations)} +func NewNamespaceMutator(name string) Mutator[*v1.Namespace] { + return &namespaceMutator{name: name, meta: NewMetadataMutator()} } func (m *namespaceMutator) String() string { diff --git a/pkg/resources/namespace_test.go b/pkg/resources/namespace_test.go index 26a28bc..5515b95 100644 --- a/pkg/resources/namespace_test.go +++ b/pkg/resources/namespace_test.go @@ -40,7 +40,8 @@ var _ = Describe("NamespaceMutator", func() { annotations = map[string]string{"annotation1": "value1"} // Create a namespace mutator - mutator = resources.NewNamespaceMutator("test-namespace", labels, annotations) + mutator = resources.NewNamespaceMutator("test-namespace") + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) }) It("should create an empty namespace with correct metadata", func() { diff --git a/pkg/resources/role.go b/pkg/resources/role.go index cbd1f2c..abe81b9 100644 --- a/pkg/resources/role.go +++ b/pkg/resources/role.go @@ -16,12 +16,12 @@ type RoleMutator struct { var _ Mutator[*v1.Role] = &RoleMutator{} -func NewRoleMutator(name, namespace string, rules []v1.PolicyRule, labels map[string]string, annotations map[string]string) Mutator[*v1.Role] { +func NewRoleMutator(name, namespace string, rules []v1.PolicyRule) Mutator[*v1.Role] { return &RoleMutator{ Name: name, Namespace: namespace, Rules: rules, - meta: NewMetadataMutator(labels, annotations), + meta: NewMetadataMutator(), } } diff --git a/pkg/resources/role_test.go b/pkg/resources/role_test.go index 5b2f17e..7ee3b60 100644 --- a/pkg/resources/role_test.go +++ b/pkg/resources/role_test.go @@ -48,7 +48,8 @@ var _ = Describe("RoleMutator", func() { annotations = map[string]string{"annotation1": "value1"} // Create a role mutator - mutator = resources.NewRoleMutator("test-role", "test-namespace", rules, labels, annotations) + mutator = resources.NewRoleMutator("test-role", "test-namespace", rules) + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) }) It("should create an empty role with correct metadata", func() { diff --git a/pkg/resources/rolebinding.go b/pkg/resources/rolebinding.go index 00f26af..e97b67f 100644 --- a/pkg/resources/rolebinding.go +++ b/pkg/resources/rolebinding.go @@ -17,13 +17,13 @@ type RoleBindingMutator struct { var _ Mutator[*v1.RoleBinding] = &RoleBindingMutator{} -func NewRoleBindingMutator(name, namespace string, subjects []v1.Subject, roleRef v1.RoleRef, labels map[string]string, annotations map[string]string) Mutator[*v1.RoleBinding] { +func NewRoleBindingMutator(name, namespace string, subjects []v1.Subject, roleRef v1.RoleRef) Mutator[*v1.RoleBinding] { return &RoleBindingMutator{ Name: name, Namespace: namespace, Subjects: subjects, RoleRef: roleRef, - meta: NewMetadataMutator(labels, annotations), + meta: NewMetadataMutator(), } } diff --git a/pkg/resources/rolebinding_test.go b/pkg/resources/rolebinding_test.go index 6c633c6..933dc8f 100644 --- a/pkg/resources/rolebinding_test.go +++ b/pkg/resources/rolebinding_test.go @@ -50,7 +50,8 @@ var _ = Describe("RoleBindingMutator", func() { annotations = map[string]string{"annotation1": "value1"} // Create a role binding mutator - mutator = resources.NewRoleBindingMutator("test-rolebinding", "test-namespace", subjects, roleRef, labels, annotations) + mutator = resources.NewRoleBindingMutator("test-rolebinding", "test-namespace", subjects, roleRef) + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) }) It("should create an empty role binding with correct metadata", func() { diff --git a/pkg/resources/secret.go b/pkg/resources/secret.go index 0b2f191..1a2c6fd 100644 --- a/pkg/resources/secret.go +++ b/pkg/resources/secret.go @@ -20,23 +20,23 @@ type SecretMutator struct { var _ Mutator[*core.Secret] = &SecretMutator{} -func NewSecretMutator(name, namespace string, data map[string][]byte, secretType core.SecretType, labels map[string]string, annotations map[string]string) Mutator[*core.Secret] { +func NewSecretMutator(name, namespace string, data map[string][]byte, secretType core.SecretType) Mutator[*core.Secret] { return &SecretMutator{ Name: name, Namespace: namespace, Data: data, Type: secretType, - meta: NewMetadataMutator(labels, annotations), + meta: NewMetadataMutator(), } } -func NewSecretMutatorWithStringData(name, namespace string, stringData map[string]string, secretType core.SecretType, labels map[string]string, annotations map[string]string) Mutator[*core.Secret] { +func NewSecretMutatorWithStringData(name, namespace string, stringData map[string]string, secretType core.SecretType) Mutator[*core.Secret] { return &SecretMutator{ Name: name, Namespace: namespace, StringData: stringData, Type: secretType, - meta: NewMetadataMutator(labels, annotations), + meta: NewMetadataMutator(), } } diff --git a/pkg/resources/secret_test.go b/pkg/resources/secret_test.go index 2fda4ff..9bfae4f 100644 --- a/pkg/resources/secret_test.go +++ b/pkg/resources/secret_test.go @@ -47,7 +47,8 @@ var _ = Describe("SecretMutator", func() { }) It("should create an empty Secret with correct metadata", func() { - mutator = resources.NewSecretMutator("test-secret", "test-namespace", data, secretType, labels, annotations) + mutator = resources.NewSecretMutator("test-secret", "test-namespace", data, secretType) + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) secret := mutator.Empty() Expect(secret.Name).To(Equal("test-secret")) @@ -60,7 +61,8 @@ var _ = Describe("SecretMutator", func() { }) It("should create an empty Secret with correct metadata (string data)", func() { - mutator = resources.NewSecretMutatorWithStringData("test-secret", "test-namespace", stringData, secretType, labels, annotations) + mutator = resources.NewSecretMutatorWithStringData("test-secret", "test-namespace", stringData, secretType) + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) secret := mutator.Empty() Expect(secret.Name).To(Equal("test-secret")) @@ -73,7 +75,8 @@ var _ = Describe("SecretMutator", func() { }) It("should apply data, labels, and annotations using Mutate", func() { - mutator = resources.NewSecretMutator("test-secret", "test-namespace", data, secretType, labels, annotations) + mutator = resources.NewSecretMutator("test-secret", "test-namespace", data, secretType) + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) secret := mutator.Empty() // Apply the mutator's Mutate method @@ -87,7 +90,8 @@ var _ = Describe("SecretMutator", func() { }) It("should apply data, labels, and annotations using Mutate (string data)", func() { - mutator = resources.NewSecretMutatorWithStringData("test-secret", "test-namespace", stringData, secretType, labels, annotations) + mutator = resources.NewSecretMutatorWithStringData("test-secret", "test-namespace", stringData, secretType) + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) secret := mutator.Empty() // Apply the mutator's Mutate method @@ -101,7 +105,8 @@ var _ = Describe("SecretMutator", func() { }) It("should create and retrieve the Secret using the fake client", func() { - mutator = resources.NewSecretMutator("test-secret", "test-namespace", data, secretType, labels, annotations) + mutator = resources.NewSecretMutator("test-secret", "test-namespace", data, secretType) + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) secret := mutator.Empty() Expect(mutator.Mutate(secret)).To(Succeed()) diff --git a/pkg/resources/serviceaccount.go b/pkg/resources/serviceaccount.go index 3d3d79c..457d5c3 100644 --- a/pkg/resources/serviceaccount.go +++ b/pkg/resources/serviceaccount.go @@ -15,11 +15,11 @@ type ServiceAccountMutator struct { var _ Mutator[*core.ServiceAccount] = &ServiceAccountMutator{} -func NewServiceAccountMutator(name, namespace string, labels map[string]string, annotations map[string]string) Mutator[*core.ServiceAccount] { +func NewServiceAccountMutator(name, namespace string) Mutator[*core.ServiceAccount] { return &ServiceAccountMutator{ Name: name, Namespace: namespace, - meta: NewMetadataMutator(labels, annotations), + meta: NewMetadataMutator(), } } diff --git a/pkg/resources/serviceaccount_test.go b/pkg/resources/serviceaccount_test.go index 4d5ebc1..6199b25 100644 --- a/pkg/resources/serviceaccount_test.go +++ b/pkg/resources/serviceaccount_test.go @@ -40,7 +40,8 @@ var _ = Describe("ServiceAccountMutator", func() { annotations = map[string]string{"annotation1": "value1"} // Create a ServiceAccount mutator - mutator = resources.NewServiceAccountMutator("test-serviceaccount", "test-namespace", labels, annotations) + mutator = resources.NewServiceAccountMutator("test-serviceaccount", "test-namespace") + mutator.MetadataMutator().WithLabels(labels).WithAnnotations(annotations) }) It("should create an empty ServiceAccount with correct metadata", func() {