Browse Source

feat: Allow adding finalizers from template (#5140)

* Allow adding finalizers from template

Signed-off-by: Michael Malov <14035243+malovme@users.noreply.github.com>

* add finalizers to full-external-secret.yaml

Signed-off-by: Michael Malov <14035243+malovme@users.noreply.github.com>

---------

Signed-off-by: Michael Malov <14035243+malovme@users.noreply.github.com>
Michael Malov 9 months ago
parent
commit
31c4304bb4

+ 3 - 0
apis/externalsecrets/v1/externalsecret_types.go

@@ -83,6 +83,9 @@ type ExternalSecretTemplateMetadata struct {
 
 	// +optional
 	Labels map[string]string `json:"labels,omitempty"`
+
+	// +optional
+	Finalizers []string `json:"finalizers,omitempty"`
 }
 
 // ExternalSecretTemplate defines a blueprint for the created Secret resource.

+ 5 - 0
apis/externalsecrets/v1/zz_generated.deepcopy.go

@@ -1641,6 +1641,11 @@ func (in *ExternalSecretTemplateMetadata) DeepCopyInto(out *ExternalSecretTempla
 			(*out)[key] = val
 		}
 	}
+	if in.Finalizers != nil {
+		in, out := &in.Finalizers, &out.Finalizers
+		*out = make([]string, len(*in))
+		copy(*out, *in)
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalSecretTemplateMetadata.

+ 4 - 0
config/crds/bases/external-secrets.io_clusterexternalsecrets.yaml

@@ -548,6 +548,10 @@ spec:
                                 additionalProperties:
                                   type: string
                                 type: object
+                              finalizers:
+                                items:
+                                  type: string
+                                type: array
                               labels:
                                 additionalProperties:
                                   type: string

+ 4 - 0
config/crds/bases/external-secrets.io_clusterpushsecrets.yaml

@@ -377,6 +377,10 @@ spec:
                             additionalProperties:
                               type: string
                             type: object
+                          finalizers:
+                            items:
+                              type: string
+                            type: array
                           labels:
                             additionalProperties:
                               type: string

+ 4 - 0
config/crds/bases/external-secrets.io_externalsecrets.yaml

@@ -526,6 +526,10 @@ spec:
                             additionalProperties:
                               type: string
                             type: object
+                          finalizers:
+                            items:
+                              type: string
+                            type: array
                           labels:
                             additionalProperties:
                               type: string

+ 4 - 0
config/crds/bases/external-secrets.io_pushsecrets.yaml

@@ -300,6 +300,10 @@ spec:
                         additionalProperties:
                           type: string
                         type: object
+                      finalizers:
+                        items:
+                          type: string
+                        type: array
                       labels:
                         additionalProperties:
                           type: string

+ 16 - 0
deploy/crds/bundle.yaml

@@ -521,6 +521,10 @@ spec:
                                   additionalProperties:
                                     type: string
                                   type: object
+                                finalizers:
+                                  items:
+                                    type: string
+                                  type: array
                                 labels:
                                   additionalProperties:
                                     type: string
@@ -1851,6 +1855,10 @@ spec:
                               additionalProperties:
                                 type: string
                               type: object
+                            finalizers:
+                              items:
+                                type: string
+                              type: array
                             labels:
                               additionalProperties:
                                 type: string
@@ -11607,6 +11615,10 @@ spec:
                               additionalProperties:
                                 type: string
                               type: object
+                            finalizers:
+                              items:
+                                type: string
+                              type: array
                             labels:
                               additionalProperties:
                                 type: string
@@ -12643,6 +12655,10 @@ spec:
                           additionalProperties:
                             type: string
                           type: object
+                        finalizers:
+                          items:
+                            type: string
+                          type: array
                         labels:
                           additionalProperties:
                             type: string

+ 11 - 0
docs/api/spec.md

@@ -4596,6 +4596,17 @@ map[string]string
 <em>(Optional)</em>
 </td>
 </tr>
+<tr>
+<td>
+<code>finalizers</code></br>
+<em>
+[]string
+</em>
+</td>
+<td>
+<em>(Optional)</em>
+</td>
+</tr>
 </tbody>
 </table>
 <h3 id="external-secrets.io/v1.ExternalSecretValidator">ExternalSecretValidator

+ 4 - 0
docs/snippets/full-external-secret.yaml

@@ -58,6 +58,10 @@ spec:
       metadata:
         annotations: {}
         labels: {}
+        # The finalizers will be added to the Secret.
+        # It is expected that finalizers will be deleted with custom cleanup functionality.
+        # This is required when another chart depends on the Secret, and it is needed to prevent the Secret from being deleted too early.
+        finalizers: []
 
       # Use inline templates to construct your desired config file that contains your secret
       data:

+ 1 - 0
e2e/suites/provider/cases/common/common.go

@@ -204,6 +204,7 @@ func JSONDataWithTemplate(f *framework.Framework) (string, func(*framework.TestC
 				Labels: map[string]string{
 					"example": "label",
 				},
+				Finalizers: []string{"example.com/finalizer"},
 			},
 			Data: map[string]string{
 				"my-data": "executed: {{ .one }}|{{ .two }}",

+ 12 - 1
pkg/controllers/externalsecret/externalsecret_controller_template.go

@@ -20,6 +20,7 @@ import (
 	"maps"
 
 	v1 "k8s.io/api/core/v1"
+	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
 
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 	"github.com/external-secrets/external-secrets/pkg/controllers/templating"
@@ -35,7 +36,7 @@ import (
 // * secret via es.data or es.dataFrom (if template.MergePolicy is Merge, or there is no template)
 // * existing secret keys (if CreationPolicy is Merge).
 func (r *Reconciler) ApplyTemplate(ctx context.Context, es *esv1.ExternalSecret, secret *v1.Secret, dataMap map[string][]byte) error {
-	// update metadata (labels, annotations) of the secret
+	// update metadata (labels, annotations, finalizers) of the secret
 	if err := setMetadata(secret, es); err != nil {
 		return err
 	}
@@ -142,5 +143,15 @@ func setMetadata(secret *v1.Secret, es *esv1.ExternalSecret) error {
 	// copy labels and annotations from the template
 	utils.MergeStringMap(secret.ObjectMeta.Labels, es.Spec.Target.Template.Metadata.Labels)
 	utils.MergeStringMap(secret.ObjectMeta.Annotations, es.Spec.Target.Template.Metadata.Annotations)
+
+	// add finalizers from the template
+	if secret.ObjectMeta.DeletionTimestamp.IsZero() {
+		for _, finalizer := range es.Spec.Target.Template.Metadata.Finalizers {
+			if !controllerutil.ContainsFinalizer(secret, finalizer) {
+				controllerutil.AddFinalizer(secret, finalizer)
+			}
+		}
+	}
+
 	return nil
 }

+ 20 - 4
pkg/controllers/externalsecret/externalsecret_controller_test.go

@@ -870,7 +870,7 @@ var _ = Describe("ExternalSecret controller", Serial, func() {
 	}
 
 	// when using a template it should be used as a blueprint
-	// to construct a new secret: labels, annotations and type
+	// to construct a new secret: labels, annotations, finalizers and type
 	syncWithTemplate := func(tc *testCase) {
 		const secretVal = "someValue"
 		const tplStaticKey = "tplstatickey"
@@ -889,6 +889,9 @@ var _ = Describe("ExternalSecret controller", Serial, func() {
 				Annotations: map[string]string{
 					"hihi": "ga",
 				},
+				Finalizers: []string{
+					"example.com/finalizer",
+				},
 			},
 			Type:          v1.SecretTypeOpaque,
 			EngineVersion: esv1.TemplateEngineV2,
@@ -903,7 +906,7 @@ var _ = Describe("ExternalSecret controller", Serial, func() {
 			Expect(string(secret.Data[targetProp])).To(Equal(expectedSecretVal))
 			Expect(string(secret.Data[tplStaticKey])).To(Equal(tplStaticVal))
 
-			// labels/annotations should be taken from the template
+			// labels/annotations/finalizers should be taken from the template
 			for k, v := range es.Spec.Target.Template.Metadata.Labels {
 				Expect(secret.ObjectMeta.Labels).To(HaveKeyWithValue(k, v))
 
@@ -911,6 +914,9 @@ var _ = Describe("ExternalSecret controller", Serial, func() {
 			for k, v := range es.Spec.Target.Template.Metadata.Annotations {
 				Expect(secret.ObjectMeta.Annotations).To(HaveKeyWithValue(k, v))
 			}
+			for _, v := range es.Spec.Target.Template.Metadata.Finalizers {
+				Expect(secret.ObjectMeta.Finalizers).To(ContainElement(v))
+			}
 		}
 	}
 
@@ -1152,6 +1158,7 @@ var _ = Describe("ExternalSecret controller", Serial, func() {
 			Metadata: esv1.ExternalSecretTemplateMetadata{
 				Labels:      map[string]string{"foo": "bar"},
 				Annotations: map[string]string{"foo": "bar"},
+				Finalizers:  []string{"example.com/finalizer"},
 			},
 			Type: v1.SecretTypeOpaque,
 			Data: map[string]string{
@@ -1165,7 +1172,7 @@ var _ = Describe("ExternalSecret controller", Serial, func() {
 			Expect(string(secret.Data[targetProp])).To(Equal(expectedSecretVal))
 			Expect(string(secret.Data[tplStaticKey])).To(Equal(tplStaticVal))
 
-			// labels/annotations should be taken from the template
+			// labels/annotations/finalizers should be taken from the template
 			for k, v := range es.Spec.Target.Template.Metadata.Labels {
 				Expect(secret.ObjectMeta.Labels).To(HaveKeyWithValue(k, v))
 
@@ -1177,6 +1184,10 @@ var _ = Describe("ExternalSecret controller", Serial, func() {
 				Expect(secret.ObjectMeta.Annotations).To(HaveKeyWithValue(k, v))
 			}
 
+			for _, v := range es.Spec.Target.Template.Metadata.Finalizers {
+				Expect(secret.ObjectMeta.Finalizers).To(ContainElement(v))
+			}
+
 			cleanEs := tc.externalSecret.DeepCopy()
 
 			// now update ExternalSecret
@@ -1218,6 +1229,7 @@ var _ = Describe("ExternalSecret controller", Serial, func() {
 			Metadata: esv1.ExternalSecretTemplateMetadata{
 				Labels:      map[string]string{"foo": "bar"},
 				Annotations: map[string]string{"foo": "bar"},
+				Finalizers:  []string{"example.com/finalizer"},
 			},
 		}
 		fakeProvider.WithGetSecret([]byte(secretVal), nil)
@@ -1225,7 +1237,7 @@ var _ = Describe("ExternalSecret controller", Serial, func() {
 			// check values
 			Expect(string(secret.Data[targetProp])).To(Equal(secretVal))
 
-			// labels/annotations should be taken from the template
+			// labels/annotations/finalizers should be taken from the template
 			for k, v := range es.Spec.Target.Template.Metadata.Labels {
 				Expect(secret.ObjectMeta.Labels).To(HaveKeyWithValue(k, v))
 			}
@@ -1233,6 +1245,10 @@ var _ = Describe("ExternalSecret controller", Serial, func() {
 			for k, v := range es.Spec.Target.Template.Metadata.Annotations {
 				Expect(secret.ObjectMeta.Annotations).To(HaveKeyWithValue(k, v))
 			}
+
+			for _, v := range es.Spec.Target.Template.Metadata.Finalizers {
+				Expect(secret.ObjectMeta.Finalizers).To(ContainElement(v))
+			}
 		}
 	}
 

+ 2 - 0
pkg/controllers/pushsecret/pushsecret_controller_test.go

@@ -429,6 +429,7 @@ var _ = Describe("PushSecret controller", func() {
 						Annotations: map[string]string{
 							"hihi": "ga",
 						},
+						Finalizers: []string{"example.com/finalizer"},
 					},
 					Type:          v1.SecretTypeOpaque,
 					EngineVersion: esv1.TemplateEngineV2,
@@ -493,6 +494,7 @@ var _ = Describe("PushSecret controller", func() {
 						Annotations: map[string]string{
 							"hihi": "ga",
 						},
+						Finalizers: []string{"example.com/finalizer"},
 					},
 					Type:          v1.SecretTypeOpaque,
 					EngineVersion: esv1.TemplateEngineV2,