From 504b32ba4331c1881df9d2d899f76726a6f877e6 Mon Sep 17 00:00:00 2001 From: Lukasz Zajaczkowski Date: Tue, 17 Dec 2024 09:22:12 +0100 Subject: [PATCH] add configurationRef to GeneratedSecret --- ...eployments.plural.sh_generatedsecrets.yaml | 14 +++++++++ .../api/v1alpha1/generatedsecret_types.go | 5 ++++ .../api/v1alpha1/zz_generated.deepcopy.go | 5 ++++ ...eployments.plural.sh_generatedsecrets.yaml | 14 +++++++++ .../controller/generatedsecret_controller.go | 29 ++++++++++++++++++- .../generatedsecret_controller_test.go | 22 ++++++++++++++ ...eployments.plural.sh_generatedsecrets.yaml | 14 +++++++++ 7 files changed, 102 insertions(+), 1 deletion(-) diff --git a/charts/controller/crds/deployments.plural.sh_generatedsecrets.yaml b/charts/controller/crds/deployments.plural.sh_generatedsecrets.yaml index eb6aadcd7..5ac0f9ce3 100644 --- a/charts/controller/crds/deployments.plural.sh_generatedsecrets.yaml +++ b/charts/controller/crds/deployments.plural.sh_generatedsecrets.yaml @@ -39,6 +39,20 @@ spec: spec: description: GeneratedSecretSpec defines the desired state of GeneratedSecret properties: + configurationRef: + description: ConfigurationRef is a secret reference which should contain + data for secrets. + properties: + name: + description: name is unique within a namespace to reference a + secret resource. + type: string + namespace: + description: namespace defines the space within which the secret + name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic destinations: description: Destinations describe name/namespace for the secrets. items: diff --git a/go/controller/api/v1alpha1/generatedsecret_types.go b/go/controller/api/v1alpha1/generatedsecret_types.go index bc121612b..72bad82ec 100644 --- a/go/controller/api/v1alpha1/generatedsecret_types.go +++ b/go/controller/api/v1alpha1/generatedsecret_types.go @@ -11,9 +11,14 @@ import ( // GeneratedSecretSpec defines the desired state of GeneratedSecret type GeneratedSecretSpec struct { // Template secret data in string form. + // +kubebuilder:validation:Optional Template map[string]string `json:"template,omitempty"` // Destinations describe name/namespace for the secrets. Destinations []GeneratedSecretDestination `json:"destinations,omitempty"` + + // ConfigurationRef is a secret reference which should contain data for secrets. + // +kubebuilder:validation:Optional + ConfigurationRef *corev1.SecretReference `json:"configurationRef,omitempty"` } type GeneratedSecretDestination struct { diff --git a/go/controller/api/v1alpha1/zz_generated.deepcopy.go b/go/controller/api/v1alpha1/zz_generated.deepcopy.go index 79f02097b..72e6d4f61 100644 --- a/go/controller/api/v1alpha1/zz_generated.deepcopy.go +++ b/go/controller/api/v1alpha1/zz_generated.deepcopy.go @@ -1551,6 +1551,11 @@ func (in *GeneratedSecretSpec) DeepCopyInto(out *GeneratedSecretSpec) { *out = make([]GeneratedSecretDestination, len(*in)) copy(*out, *in) } + if in.ConfigurationRef != nil { + in, out := &in.ConfigurationRef, &out.ConfigurationRef + *out = new(v1.SecretReference) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeneratedSecretSpec. diff --git a/go/controller/config/crd/bases/deployments.plural.sh_generatedsecrets.yaml b/go/controller/config/crd/bases/deployments.plural.sh_generatedsecrets.yaml index eb6aadcd7..5ac0f9ce3 100644 --- a/go/controller/config/crd/bases/deployments.plural.sh_generatedsecrets.yaml +++ b/go/controller/config/crd/bases/deployments.plural.sh_generatedsecrets.yaml @@ -39,6 +39,20 @@ spec: spec: description: GeneratedSecretSpec defines the desired state of GeneratedSecret properties: + configurationRef: + description: ConfigurationRef is a secret reference which should contain + data for secrets. + properties: + name: + description: name is unique within a namespace to reference a + secret resource. + type: string + namespace: + description: namespace defines the space within which the secret + name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic destinations: description: Destinations describe name/namespace for the secrets. items: diff --git a/go/controller/internal/controller/generatedsecret_controller.go b/go/controller/internal/controller/generatedsecret_controller.go index 2770b3b7d..1e11d73cc 100644 --- a/go/controller/internal/controller/generatedsecret_controller.go +++ b/go/controller/internal/controller/generatedsecret_controller.go @@ -60,7 +60,13 @@ func (r *GeneratedSecretReconciler) Reconcile(ctx context.Context, req ctrl.Requ return r.handleDelete(ctx, generatedSecret) } - data, err := r.persistData(ctx, generatedSecret, generatedSecret.Spec.Template) + tmp, err := r.prepareTemplateData(ctx, generatedSecret) + if err != nil { + utils.MarkCondition(generatedSecret.SetCondition, v1alpha1.ReadyConditionType, v1.ConditionFalse, v1alpha1.SynchronizedConditionReasonError, err.Error()) + return ctrl.Result{}, err + } + + data, err := r.persistData(ctx, generatedSecret, tmp) if err != nil { utils.MarkCondition(generatedSecret.SetCondition, v1alpha1.ReadyConditionType, v1.ConditionFalse, v1alpha1.SynchronizedConditionReasonError, err.Error()) return ctrl.Result{}, err @@ -104,6 +110,27 @@ func (r *GeneratedSecretReconciler) Reconcile(ctx context.Context, req ctrl.Requ return ctrl.Result{}, nil } +func (r *GeneratedSecretReconciler) prepareTemplateData(ctx context.Context, generatedSecret *v1alpha1.GeneratedSecret) (map[string]string, error) { + data := make(map[string]string) + if generatedSecret.Spec.Template == nil { + generatedSecret.Spec.Template = make(map[string]string) + } + + if generatedSecret.Spec.ConfigurationRef != nil { + secretRef := &corev1.SecretReference{Name: generatedSecret.Spec.ConfigurationRef.Name, Namespace: generatedSecret.Spec.ConfigurationRef.Namespace} + secret, err := utils.GetSecret(ctx, r.Client, secretRef) + if err != nil { + return nil, err + } + for k, v := range secret.Data { + value := string(v) + data[k] = value + } + } + data = lo.Assign(data, generatedSecret.Spec.Template) + return data, nil +} + func (r *GeneratedSecretReconciler) persistData(ctx context.Context, gs *v1alpha1.GeneratedSecret, tmp map[string]string) (map[string][]byte, error) { data, err := templateData(tmp) if err != nil { diff --git a/go/controller/internal/controller/generatedsecret_controller_test.go b/go/controller/internal/controller/generatedsecret_controller_test.go index c4d07d350..edd80677f 100644 --- a/go/controller/internal/controller/generatedsecret_controller_test.go +++ b/go/controller/internal/controller/generatedsecret_controller_test.go @@ -7,6 +7,7 @@ import ( . "github.com/onsi/gomega" "github.com/pluralsh/console/go/controller/api/v1alpha1" "github.com/pluralsh/console/go/controller/internal/controller" + common "github.com/pluralsh/console/go/controller/internal/test/common" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -18,6 +19,7 @@ import ( var _ = Describe("GeneratedSecret Controller", Ordered, func() { Context("When reconciling a resource", func() { const ( + configSecretName = "config" generatedSecretName = "test" namespace = "default" ) @@ -29,6 +31,16 @@ var _ = Describe("GeneratedSecret Controller", Ordered, func() { gs := &v1alpha1.GeneratedSecret{} BeforeAll(func() { + By("Creating configuration secret") + Expect(common.MaybeCreate(k8sClient, &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: configSecretName, + Namespace: "default", + }, + Data: map[string][]byte{ + "a": []byte("b"), + }, + }, nil)).To(Succeed()) By("Creating GeneratedSecret") err := k8sClient.Get(ctx, namespacedName, gs) if err != nil && errors.IsNotFound(err) { @@ -38,6 +50,10 @@ var _ = Describe("GeneratedSecret Controller", Ordered, func() { Namespace: namespace, }, Spec: v1alpha1.GeneratedSecretSpec{ + ConfigurationRef: &corev1.SecretReference{ + Name: configSecretName, + Namespace: namespace, + }, Template: map[string]string{ "b64": "{{ 'one two three' | b64enc }}", "name": "John Doe", @@ -53,6 +69,7 @@ var _ = Describe("GeneratedSecret Controller", Ordered, func() { } Expect(k8sClient.Create(ctx, resource)).To(Succeed()) } + }) AfterAll(func() { @@ -60,6 +77,9 @@ var _ = Describe("GeneratedSecret Controller", Ordered, func() { gs := &v1alpha1.GeneratedSecret{} Expect(k8sClient.Get(ctx, namespacedName, gs)).NotTo(HaveOccurred()) Expect(k8sClient.Delete(ctx, gs)).To(Succeed()) + configSecret := &corev1.Secret{} + Expect(k8sClient.Get(ctx, types.NamespacedName{Name: configSecretName, Namespace: namespace}, configSecret)).NotTo(HaveOccurred()) + Expect(k8sClient.Delete(ctx, configSecret)).To(Succeed()) }) It("Reconcile test", func() { @@ -75,6 +95,8 @@ var _ = Describe("GeneratedSecret Controller", Ordered, func() { Expect(k8sClient.Get(ctx, client.ObjectKey{Name: "secret1", Namespace: namespace}, s1)).To(Succeed()) Expect(s1.Data["b64"]).To(Equal([]byte("b25lIHR3byB0aHJlZQ=="))) Expect(s1.Data["name"]).To(Equal([]byte("John Doe"))) + // from configurationRef + Expect(s1.Data["a"]).To(Equal([]byte("b"))) password := s1.Data["password"] Expect(len(password)).To(Equal(10)) diff --git a/plural/helm/console/crds/deployments.plural.sh_generatedsecrets.yaml b/plural/helm/console/crds/deployments.plural.sh_generatedsecrets.yaml index eb6aadcd7..5ac0f9ce3 100644 --- a/plural/helm/console/crds/deployments.plural.sh_generatedsecrets.yaml +++ b/plural/helm/console/crds/deployments.plural.sh_generatedsecrets.yaml @@ -39,6 +39,20 @@ spec: spec: description: GeneratedSecretSpec defines the desired state of GeneratedSecret properties: + configurationRef: + description: ConfigurationRef is a secret reference which should contain + data for secrets. + properties: + name: + description: name is unique within a namespace to reference a + secret resource. + type: string + namespace: + description: namespace defines the space within which the secret + name must be unique. + type: string + type: object + x-kubernetes-map-type: atomic destinations: description: Destinations describe name/namespace for the secrets. items: