From 30cd4287ded0a4e58d7ef6859d324ee7774e99df Mon Sep 17 00:00:00 2001 From: Laurence Robinson Date: Wed, 20 Aug 2025 10:37:07 -0400 Subject: [PATCH] add support for PVC retention policy Signed-off-by: Laurence Robinson --- api/v1alpha1/dragonfly_types.go | 6 +++ api/v1alpha1/zz_generated.deepcopy.go | 6 +++ .../crd/bases/dragonflydb.io_dragonflies.yaml | 19 ++++++++++ e2e/dragonfly_controller_test.go | 37 +++++++++++++++++++ internal/resources/resources.go | 4 ++ manifests/crd.yaml | 19 ++++++++++ manifests/dragonfly-operator.yaml | 19 ++++++++++ 7 files changed, 110 insertions(+) diff --git a/api/v1alpha1/dragonfly_types.go b/api/v1alpha1/dragonfly_types.go index 0f1c575..738d1aa 100644 --- a/api/v1alpha1/dragonfly_types.go +++ b/api/v1alpha1/dragonfly_types.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha1 import ( + appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -169,6 +170,11 @@ type DragonflySpec struct { // +optional // +kubebuilder:validation:Optional InitContainers []corev1.Container `json:"initContainers,omitempty"` + + // (Optional) StatefulSet PVC Retention Policy + // +optional + // +kubebuilder:validation:Optional + PersistentVolumeClaimRetentionPolicy *appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy `json:"persistentVolumeClaimRetentionPolicy,omitempty"` } type ServiceSpec struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 629251f..670590b 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -21,6 +21,7 @@ limitations under the License. package v1alpha1 import ( + appsv1 "k8s.io/api/apps/v1" "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -235,6 +236,11 @@ func (in *DragonflySpec) DeepCopyInto(out *DragonflySpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.PersistentVolumeClaimRetentionPolicy != nil { + in, out := &in.PersistentVolumeClaimRetentionPolicy, &out.PersistentVolumeClaimRetentionPolicy + *out = new(appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DragonflySpec. diff --git a/config/crd/bases/dragonflydb.io_dragonflies.yaml b/config/crd/bases/dragonflydb.io_dragonflies.yaml index 84d72d9..b67ea6a 100644 --- a/config/crd/bases/dragonflydb.io_dragonflies.yaml +++ b/config/crd/bases/dragonflydb.io_dragonflies.yaml @@ -6043,6 +6043,25 @@ spec: type: string description: (Optional) Dragonfly pod node selector type: object + persistentVolumeClaimRetentionPolicy: + description: (Optional) StatefulSet PVC Retention Policy + properties: + whenDeleted: + description: |- + WhenDeleted specifies what happens to PVCs created from StatefulSet + VolumeClaimTemplates when the StatefulSet is deleted. The default policy + of `Retain` causes PVCs to not be affected by StatefulSet deletion. The + `Delete` policy causes those PVCs to be deleted. + type: string + whenScaled: + description: |- + WhenScaled specifies what happens to PVCs created from StatefulSet + VolumeClaimTemplates when the StatefulSet is scaled down. The default + policy of `Retain` causes PVCs to not be affected by a scaledown. The + `Delete` policy causes the associated PVCs for any excess pods above + the replica count to be deleted. + type: string + type: object podSecurityContext: description: (Optional) Dragonfly pod security context properties: diff --git a/e2e/dragonfly_controller_test.go b/e2e/dragonfly_controller_test.go index e1b142f..3679d91 100644 --- a/e2e/dragonfly_controller_test.go +++ b/e2e/dragonfly_controller_test.go @@ -547,6 +547,43 @@ var _ = Describe("Dragonfly Lifecycle tests", Ordered, FlakeAttempts(3), func() Expect(svc.Labels).To(Equal(newLabels)) }) + It("Check for PVC retention policy", func() { + err := k8sClient.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &df) + Expect(err).To(BeNil()) + + var ss appsv1.StatefulSet + err = k8sClient.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &ss) + Expect(err).To(BeNil()) + + Expect(ss.Spec.PersistentVolumeClaimRetentionPolicy).To(Equal(&appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy{ + WhenDeleted: appsv1.RetainPersistentVolumeClaimRetentionPolicyType, + })) + + df.Spec.PersistentVolumeClaimRetentionPolicy = &appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy{ + WhenDeleted: appsv1.DeletePersistentVolumeClaimRetentionPolicyType, + } + + err = k8sClient.Update(ctx, &df) + Expect(err).To(BeNil()) + + err = waitForStatefulSetReady(ctx, k8sClient, name, namespace, 3*time.Minute) + Expect(err).To(BeNil()) + + err = k8sClient.Get(ctx, types.NamespacedName{ + Name: name, + Namespace: namespace, + }, &ss) + Expect(err).To(BeNil()) + + Expect(ss.Spec.PersistentVolumeClaimRetentionPolicy).To(Equal(df.Spec.PersistentVolumeClaimRetentionPolicy)) + }) + It("Should recreate missing statefulset", func() { var ss appsv1.StatefulSet err := k8sClient.Get(ctx, types.NamespacedName{ diff --git a/internal/resources/resources.go b/internal/resources/resources.go index 3ffbb63..6965d39 100644 --- a/internal/resources/resources.go +++ b/internal/resources/resources.go @@ -369,6 +369,10 @@ func GenerateDragonflyResources(df *resourcesv1.Dragonfly) ([]client.Object, err } } + if df.Spec.PersistentVolumeClaimRetentionPolicy != nil { + statefulset.Spec.PersistentVolumeClaimRetentionPolicy = df.Spec.PersistentVolumeClaimRetentionPolicy + } + statefulset.Spec.Template.Spec.Containers = mergeNamedSlices( statefulset.Spec.Template.Spec.Containers, df.Spec.AdditionalContainers, func(c corev1.Container) string { return c.Name }) diff --git a/manifests/crd.yaml b/manifests/crd.yaml index 9efbde7..28bf777 100644 --- a/manifests/crd.yaml +++ b/manifests/crd.yaml @@ -6042,6 +6042,25 @@ spec: type: string description: (Optional) Dragonfly pod node selector type: object + persistentVolumeClaimRetentionPolicy: + description: (Optional) StatefulSet PVC Retention Policy + properties: + whenDeleted: + description: |- + WhenDeleted specifies what happens to PVCs created from StatefulSet + VolumeClaimTemplates when the StatefulSet is deleted. The default policy + of `Retain` causes PVCs to not be affected by StatefulSet deletion. The + `Delete` policy causes those PVCs to be deleted. + type: string + whenScaled: + description: |- + WhenScaled specifies what happens to PVCs created from StatefulSet + VolumeClaimTemplates when the StatefulSet is scaled down. The default + policy of `Retain` causes PVCs to not be affected by a scaledown. The + `Delete` policy causes the associated PVCs for any excess pods above + the replica count to be deleted. + type: string + type: object podSecurityContext: description: (Optional) Dragonfly pod security context properties: diff --git a/manifests/dragonfly-operator.yaml b/manifests/dragonfly-operator.yaml index 35e149a..8c76068 100644 --- a/manifests/dragonfly-operator.yaml +++ b/manifests/dragonfly-operator.yaml @@ -6055,6 +6055,25 @@ spec: type: string description: (Optional) Dragonfly pod node selector type: object + persistentVolumeClaimRetentionPolicy: + description: (Optional) StatefulSet PVC Retention Policy + properties: + whenDeleted: + description: |- + WhenDeleted specifies what happens to PVCs created from StatefulSet + VolumeClaimTemplates when the StatefulSet is deleted. The default policy + of `Retain` causes PVCs to not be affected by StatefulSet deletion. The + `Delete` policy causes those PVCs to be deleted. + type: string + whenScaled: + description: |- + WhenScaled specifies what happens to PVCs created from StatefulSet + VolumeClaimTemplates when the StatefulSet is scaled down. The default + policy of `Retain` causes PVCs to not be affected by a scaledown. The + `Delete` policy causes the associated PVCs for any excess pods above + the replica count to be deleted. + type: string + type: object podSecurityContext: description: (Optional) Dragonfly pod security context properties: