diff --git a/Makefile b/Makefile index ef933b8..4f92bfc 100644 --- a/Makefile +++ b/Makefile @@ -122,7 +122,7 @@ test: manifests generate fmt vet setup-envtest ## Run tests. # The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally. # CertManager is installed by default; skip with: # - CERT_MANAGER_INSTALL_SKIP=true -KIND_CLUSTER ?= memcached-operator-test-e2e +KIND_CLUSTER ?= typesense-operator-test-e2e .PHONY: setup-test-e2e setup-test-e2e: ## Set up a Kind cluster for e2e tests if it does not exist diff --git a/api/v1alpha1/typesensecluster_types_storage.go b/api/v1alpha1/typesensecluster_types_storage.go index ec8fd4a..b5c4638 100644 --- a/api/v1alpha1/typesensecluster_types_storage.go +++ b/api/v1alpha1/typesensecluster_types_storage.go @@ -1,6 +1,9 @@ package v1alpha1 -import "k8s.io/apimachinery/pkg/api/resource" +import ( + appsv1 "k8s.io/api/apps/v1" + "k8s.io/apimachinery/pkg/api/resource" +) type StorageSpec struct { @@ -15,7 +18,11 @@ type StorageSpec struct { // +kubebuilder:default:=ReadWriteOnce AccessMode string `json:"accessMode,omitempty"` + // +kubebuilder:validation:Optional Annotations map[string]string `json:"annotations,omitempty"` + + // +kubebuilder:validation:Optional + RetentionPolicy *appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy `json:"retentionPolicy"` } func (s *TypesenseClusterSpec) GetStorage() StorageSpec { @@ -27,5 +34,20 @@ func (s *TypesenseClusterSpec) GetStorage() StorageSpec { Size: resource.MustParse("100Mi"), StorageClassName: "standard", AccessMode: "ReadWriteOnce", + RetentionPolicy: &appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy{ + WhenDeleted: appsv1.RetainPersistentVolumeClaimRetentionPolicyType, + WhenScaled: appsv1.RetainPersistentVolumeClaimRetentionPolicyType, + }, + } +} + +func (s *TypesenseClusterSpec) GetStorageRetentionPolicy() *appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy { + if s.Storage != nil && s.Storage.RetentionPolicy != nil { + return s.Storage.RetentionPolicy + } + + return &appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy{ + WhenDeleted: appsv1.RetainPersistentVolumeClaimRetentionPolicyType, + WhenScaled: appsv1.RetainPersistentVolumeClaimRetentionPolicyType, } } diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 013c000..21cb0ea 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" networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -241,6 +242,11 @@ func (in *StorageSpec) DeepCopyInto(out *StorageSpec) { (*out)[key] = val } } + if in.RetentionPolicy != nil { + in, out := &in.RetentionPolicy, &out.RetentionPolicy + *out = new(appsv1.StatefulSetPersistentVolumeClaimRetentionPolicy) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageSpec. diff --git a/charts/typesense-operator/templates/typesensecluster-crd.yaml b/charts/typesense-operator/templates/typesensecluster-crd.yaml index 0cbfd8e..f460712 100644 --- a/charts/typesense-operator/templates/typesensecluster-crd.yaml +++ b/charts/typesense-operator/templates/typesensecluster-crd.yaml @@ -4271,6 +4271,27 @@ spec: x-kubernetes-int-or-string: true storageClassName: type: string + retentionPolicy: + description: |- + StatefulSetPersistentVolumeClaimRetentionPolicy describes the policy used for PVCs + created from the StatefulSet VolumeClaimTemplates. + 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 required: - storageClassName type: object @@ -4580,4 +4601,4 @@ status: kind: "" plural: "" conditions: [] - storedVersions: [] \ No newline at end of file + storedVersions: [] diff --git a/config/crd/bases/ts.opentelekomcloud.com_typesenseclusters.yaml b/config/crd/bases/ts.opentelekomcloud.com_typesenseclusters.yaml index 336254d..044ad9a 100644 --- a/config/crd/bases/ts.opentelekomcloud.com_typesenseclusters.yaml +++ b/config/crd/bases/ts.opentelekomcloud.com_typesenseclusters.yaml @@ -4326,6 +4326,27 @@ spec: additionalProperties: type: string type: object + retentionPolicy: + description: |- + StatefulSetPersistentVolumeClaimRetentionPolicy describes the policy used for PVCs + created from the StatefulSet VolumeClaimTemplates. + 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 size: anyOf: - type: integer diff --git a/config/samples/ts_v1alpha1_typesensecluster.yaml b/config/samples/ts_v1alpha1_typesensecluster.yaml index 19f1251..4d438d0 100644 --- a/config/samples/ts_v1alpha1_typesensecluster.yaml +++ b/config/samples/ts_v1alpha1_typesensecluster.yaml @@ -10,4 +10,7 @@ spec: replicas: 3 storage: size: 100Mi - storageClassName: standard \ No newline at end of file + storageClassName: standard + retentionPolicy: + whenDeleted: Delete + whenScaled: Retain diff --git a/internal/controller/typesensecluster_statefulset.go b/internal/controller/typesensecluster_statefulset.go index 244eb1d..da1cdb0 100644 --- a/internal/controller/typesensecluster_statefulset.go +++ b/internal/controller/typesensecluster_statefulset.go @@ -486,6 +486,7 @@ func (r *TypesenseClusterReconciler) buildStatefulSet(ctx context.Context, key c }, }, }, + PersistentVolumeClaimRetentionPolicy: ts.Spec.GetStorageRetentionPolicy(), }, } diff --git a/internal/controller/typesensecluster_statefulset_hash.go b/internal/controller/typesensecluster_statefulset_hash.go index 59ae5dd..b6683d3 100644 --- a/internal/controller/typesensecluster_statefulset_hash.go +++ b/internal/controller/typesensecluster_statefulset_hash.go @@ -17,15 +17,16 @@ import ( type UpdateStatefulSetTrigger string var ( - SpecReplicasChanged UpdateStatefulSetTrigger = "SpecReplicasChanged" - HashAnnotationChanged UpdateStatefulSetTrigger = "HashAnnotationChanged" - PodAnnotationsChanged UpdateStatefulSetTrigger = "PodAnnotationsChanged" - StatefulSetAnnotationsChanged UpdateStatefulSetTrigger = "StatefulSetAnnotationsChanged" - SpecResourcesChanged UpdateStatefulSetTrigger = "SpecResourcesChanged" - PodSecurityContextChanged UpdateStatefulSetTrigger = "PodSecurityContextChanged" - InvalidContainerCount UpdateStatefulSetTrigger = "InvalidContainerCount" - ContainerSecurityContextChanged UpdateStatefulSetTrigger = "ContainerSecurityContextChanged" - SpecTypesenseVersionChanged UpdateStatefulSetTrigger = "SpecTypesenseVersionChanged" + SpecReplicasChanged UpdateStatefulSetTrigger = "SpecReplicasChanged" + HashAnnotationChanged UpdateStatefulSetTrigger = "HashAnnotationChanged" + PodAnnotationsChanged UpdateStatefulSetTrigger = "PodAnnotationsChanged" + StatefulSetAnnotationsChanged UpdateStatefulSetTrigger = "StatefulSetAnnotationsChanged" + StatefulSetARetentionPolicyChanged UpdateStatefulSetTrigger = "StatefulSetARetentionPolicyChanged" + SpecResourcesChanged UpdateStatefulSetTrigger = "SpecResourcesChanged" + PodSecurityContextChanged UpdateStatefulSetTrigger = "PodSecurityContextChanged" + InvalidContainerCount UpdateStatefulSetTrigger = "InvalidContainerCount" + ContainerSecurityContextChanged UpdateStatefulSetTrigger = "ContainerSecurityContextChanged" + SpecTypesenseVersionChanged UpdateStatefulSetTrigger = "SpecTypesenseVersionChanged" ) func (r *TypesenseClusterReconciler) shouldUpdateStatefulSet(sts *appsv1.StatefulSet, desired *appsv1.StatefulSet, ts *tsv1alpha1.TypesenseCluster) (update bool, scaleOnly bool, triggers []UpdateStatefulSetTrigger) { @@ -43,7 +44,7 @@ func (r *TypesenseClusterReconciler) shouldUpdateStatefulSet(sts *appsv1.Statefu // SpecReplicasChanged if *sts.Spec.Replicas != ts.Spec.Replicas && - (condition.Reason != string(ConditionReasonQuorumDowngraded) || condition.Reason != string(ConditionReasonQuorumQueuedWrites)) { + (condition.Reason != string(ConditionReasonQuorumDowngraded) && condition.Reason != string(ConditionReasonQuorumQueuedWrites)) { triggers = append(triggers, SpecReplicasChanged) update = false scaleOnly = true @@ -71,6 +72,12 @@ func (r *TypesenseClusterReconciler) shouldUpdateStatefulSet(sts *appsv1.Statefu update = true } + // StatefulSetARetentionPolicyChanged + if !apiequality.Semantic.DeepEqual(sts.Spec.PersistentVolumeClaimRetentionPolicy, desired.Spec.PersistentVolumeClaimRetentionPolicy) { + triggers = append(triggers, StatefulSetARetentionPolicyChanged) + update = true + } + //// SpecResourcesChanged //if !apiequality.Semantic.DeepEqual(sts.Spec.Template.Spec.Containers[0].Resources, ts.Spec.GetResources()) { // triggers = append(triggers, SpecResourcesChanged)