From beedc37a8dc2b013c6a716b111a4be444b6d17e8 Mon Sep 17 00:00:00 2001 From: Leon Date: Thu, 26 Sep 2024 09:46:54 +0800 Subject: [PATCH] chore: remove the Halt termination policy (#8202) --- apis/apps/v1/cluster_types.go | 12 +- apis/apps/v1/types.go | 1 - apis/apps/v1alpha1/cluster_conversion.go | 9 + .../bases/apps.kubeblocks.io_clusters.yaml | 6 +- controllers/apps/cluster_controller.go | 4 - controllers/apps/cluster_controller_test.go | 38 ---- controllers/apps/component_controller_test.go | 4 +- controllers/apps/transform_utils.go | 57 ------ .../apps/transformer_cluster_deletion.go | 11 +- controllers/apps/transformer_cluster_halt.go | 65 ------- .../transformer_cluster_halt_recovering.go | 175 ------------------ .../apps/transformer_component_deletion.go | 21 +-- .../crds/apps.kubeblocks.io_clusters.yaml | 6 +- docs/developer_docs/api-reference/cluster.md | 15 +- pkg/constant/annotations.go | 30 ++- pkg/controller/plan/restore.go | 14 -- 16 files changed, 37 insertions(+), 431 deletions(-) delete mode 100644 controllers/apps/transformer_cluster_halt.go delete mode 100644 controllers/apps/transformer_cluster_halt_recovering.go diff --git a/apis/apps/v1/cluster_types.go b/apis/apps/v1/cluster_types.go index 19cf1f4ca4b..a960a562f89 100644 --- a/apis/apps/v1/cluster_types.go +++ b/apis/apps/v1/cluster_types.go @@ -131,10 +131,7 @@ type ClusterSpec struct { // Choose a policy based on the desired level of resource cleanup and data preservation: // // - `DoNotTerminate`: Prevents deletion of the Cluster. This policy ensures that all resources remain intact. - // - `Halt`: Deletes Cluster resources like Pods and Services but retains Persistent Volume Claims (PVCs), - // allowing for data preservation while stopping other operations. - // - `Delete`: Extends the `Halt` policy by also removing PVCs, leading to a thorough cleanup while - // removing all persistent data. + // - `Delete`: Deletes all runtime resources belong to the Cluster. // - `WipeOut`: An aggressive policy that deletes all Cluster resources, including volume snapshots and // backups in external storage. // This results in complete data removal and should be used cautiously, primarily in non-production environments @@ -244,17 +241,14 @@ type ClusterStatus struct { // TerminationPolicyType defines termination policy types. // // +enum -// +kubebuilder:validation:Enum={DoNotTerminate,Halt,Delete,WipeOut} +// +kubebuilder:validation:Enum={DoNotTerminate,Delete,WipeOut} type TerminationPolicyType string const ( // DoNotTerminate will block delete operation. DoNotTerminate TerminationPolicyType = "DoNotTerminate" - // Halt will delete workload resources such as statefulset, deployment workloads but keep PVCs. - Halt TerminationPolicyType = "Halt" - - // Delete is based on Halt and deletes PVCs. + // Delete will delete all runtime resources belong to the cluster. Delete TerminationPolicyType = "Delete" // WipeOut is based on Delete and wipe out all volume snapshots and snapshot data from backup storage location. diff --git a/apis/apps/v1/types.go b/apis/apps/v1/types.go index 32e876c683c..fe559f01cd6 100644 --- a/apis/apps/v1/types.go +++ b/apis/apps/v1/types.go @@ -78,7 +78,6 @@ const ( ) const ( - ConditionTypeHaltRecovery = "HaltRecovery" // ConditionTypeHaltRecovery describe Halt recovery processing stage ConditionTypeProvisioningStarted = "ProvisioningStarted" // ConditionTypeProvisioningStarted the operator starts resource provisioning to create or change the cluster ConditionTypeApplyResources = "ApplyResources" // ConditionTypeApplyResources the operator start to apply resources to create or change the cluster ConditionTypeReplicasReady = "ReplicasReady" // ConditionTypeReplicasReady all pods of components are ready diff --git a/apis/apps/v1alpha1/cluster_conversion.go b/apis/apps/v1alpha1/cluster_conversion.go index 049cab8355f..237e4ba0b62 100644 --- a/apis/apps/v1alpha1/cluster_conversion.go +++ b/apis/apps/v1alpha1/cluster_conversion.go @@ -117,6 +117,11 @@ func (r *Cluster) changesToCluster(cluster *appsv1.Cluster) { if len(r.Spec.ClusterDefRef) > 0 { cluster.Spec.ClusterDef = r.Spec.ClusterDefRef } + if r.Spec.TerminationPolicy == Halt { + cluster.Spec.TerminationPolicy = appsv1.DoNotTerminate + } else { + cluster.Spec.TerminationPolicy = appsv1.TerminationPolicyType(r.Spec.TerminationPolicy) + } } func (r *Cluster) changesFromCluster(cluster *appsv1.Cluster) { @@ -140,6 +145,7 @@ func (r *Cluster) changesFromCluster(cluster *appsv1.Cluster) { if len(cluster.Spec.ClusterDef) > 0 { r.Spec.ClusterDefRef = cluster.Spec.ClusterDef } + // appsv1.TerminationPolicyType is a subset of appsv1alpha1.TerminationPolicyType, it can be converted directly. } type clusterConverter struct { @@ -149,6 +155,7 @@ type clusterConverter struct { type clusterSpecConverter struct { ClusterVersionRef string `json:"clusterVersionRef,omitempty"` + TerminationPolicy TerminationPolicyType `json:"terminationPolicy"` Affinity *Affinity `json:"affinity,omitempty"` Tolerations []corev1.Toleration `json:"tolerations,omitempty"` Tenancy TenancyType `json:"tenancy,omitempty"` @@ -186,6 +193,7 @@ type clusterCompStatusConverter struct { func (c *clusterConverter) fromCluster(cluster *Cluster) { c.Spec.ClusterVersionRef = cluster.Spec.ClusterVersionRef + c.Spec.TerminationPolicy = cluster.Spec.TerminationPolicy c.Spec.Affinity = cluster.Spec.Affinity c.Spec.Tolerations = cluster.Spec.Tolerations c.Spec.Tenancy = cluster.Spec.Tenancy @@ -227,6 +235,7 @@ func (c *clusterConverter) fromCluster(cluster *Cluster) { func (c *clusterConverter) toCluster(cluster *Cluster) { cluster.Spec.ClusterVersionRef = c.Spec.ClusterVersionRef + cluster.Spec.TerminationPolicy = c.Spec.TerminationPolicy cluster.Spec.Affinity = c.Spec.Affinity cluster.Spec.Tolerations = c.Spec.Tolerations cluster.Spec.Tenancy = c.Spec.Tenancy diff --git a/config/crd/bases/apps.kubeblocks.io_clusters.yaml b/config/crd/bases/apps.kubeblocks.io_clusters.yaml index be5aad680b6..19f781797f1 100644 --- a/config/crd/bases/apps.kubeblocks.io_clusters.yaml +++ b/config/crd/bases/apps.kubeblocks.io_clusters.yaml @@ -15884,10 +15884,7 @@ spec: - `DoNotTerminate`: Prevents deletion of the Cluster. This policy ensures that all resources remain intact. - - `Halt`: Deletes Cluster resources like Pods and Services but retains Persistent Volume Claims (PVCs), - allowing for data preservation while stopping other operations. - - `Delete`: Extends the `Halt` policy by also removing PVCs, leading to a thorough cleanup while - removing all persistent data. + - `Delete`: Deletes all runtime resources belong to the Cluster. - `WipeOut`: An aggressive policy that deletes all Cluster resources, including volume snapshots and backups in external storage. This results in complete data removal and should be used cautiously, primarily in non-production environments @@ -15898,7 +15895,6 @@ spec: The `WipeOut` policy is particularly risky in production environments due to its irreversible nature. enum: - DoNotTerminate - - Halt - Delete - WipeOut type: string diff --git a/controllers/apps/cluster_controller.go b/controllers/apps/cluster_controller.go index 5ce9be0a065..45a0ca97c86 100644 --- a/controllers/apps/cluster_controller.go +++ b/controllers/apps/cluster_controller.go @@ -127,12 +127,8 @@ func (r *ClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct // TODO: transformers are vertices, theirs' dependencies are edges, make plan Build stage a DAG. plan, errBuild := planBuilder. AddTransformer( - // handle cluster halt first - &clusterHaltTransformer{}, // handle cluster deletion &clusterDeletionTransformer{}, - // check is recovering from halted cluster - &clusterHaltRecoveryTransformer{}, // update finalizer and cd&cv labels &clusterAssureMetaTransformer{}, // validate cd & cv's existence and availability diff --git a/controllers/apps/cluster_controller_test.go b/controllers/apps/cluster_controller_test.go index f3caaff2925..a8268666938 100644 --- a/controllers/apps/cluster_controller_test.go +++ b/controllers/apps/cluster_controller_test.go @@ -784,36 +784,6 @@ var _ = Describe("Cluster Controller", func() { } } - testDeleteClusterWithHalt := func(createObj func(appsv1.TerminationPolicyType)) { - createObj(appsv1.Halt) - - transCtx := &clusterTransformContext{ - Context: testCtx.Ctx, - Client: testCtx.Cli, - } - namespacedKinds, clusteredKinds := kindsForWipeOut() - allKinds := append(namespacedKinds, clusteredKinds...) - createdObjs, err := getOwningNamespacedObjects(transCtx.Context, transCtx.Client, clusterObj.Namespace, getAppInstanceML(*clusterObj), allKinds) - Expect(err).Should(Succeed()) - - By("delete the cluster") - testapps.DeleteObject(&testCtx, clusterKey, &appsv1.Cluster{}) - Consistently(testapps.CheckObjExists(&testCtx, clusterKey, &appsv1.Cluster{}, true)).Should(Succeed()) - - By("check all cluster resources again") - objs, err := getOwningNamespacedObjects(transCtx.Context, transCtx.Client, clusterObj.Namespace, getAppInstanceML(*clusterObj), allKinds) - Expect(err).Should(Succeed()) - // check all objects existed before cluster deletion still be there - for key, obj := range createdObjs { - Expect(objs).Should(HaveKey(key)) - Expect(obj.GetUID()).Should(BeEquivalentTo(objs[key].GetUID())) - } - } - - testClusterHaltNRecovery := func(createObj func(appsv1.TerminationPolicyType)) { - // TODO(component) - } - deleteClusterWithBackup := func(terminationPolicy appsv1.TerminationPolicyType, backupRetainPolicy string) { By("mocking a retained backup") backupPolicyName := "test-backup-policy" @@ -952,14 +922,6 @@ var _ = Describe("Cluster Controller", func() { testDeleteClusterWithDoNotTerminate(createObj) }) - It("delete cluster with terminationPolicy=Halt", func() { - testDeleteClusterWithHalt(createObj) - }) - - It("cluster Halt and Recovery", func() { - testClusterHaltNRecovery(createObj) - }) - It("delete cluster with terminationPolicy=Delete", func() { testDeleteClusterWithDelete(createObj) }) diff --git a/controllers/apps/component_controller_test.go b/controllers/apps/component_controller_test.go index e88b0de48d7..31a82de54f5 100644 --- a/controllers/apps/component_controller_test.go +++ b/controllers/apps/component_controller_test.go @@ -20,7 +20,6 @@ along with this program. If not, see . package apps import ( - "encoding/json" "fmt" "strconv" "strings" @@ -362,14 +361,13 @@ var _ = Describe("Component Controller", func() { if storageSize == "" { storageSize = "1Gi" } - clusterBytes, _ := json.Marshal(clusterObj) testapps.NewPersistentVolumeClaimFactory(testCtx.DefaultNamespace, pvcName, clusterName, compName, testapps.DataVolumeName). AddLabelsInMap(map[string]string{ constant.AppInstanceLabelKey: clusterName, constant.KBAppComponentLabelKey: compName, constant.AppManagedByLabelKey: constant.AppName, - }).AddAnnotations(constant.LastAppliedClusterAnnotationKey, string(clusterBytes)). + }). SetStorage(storageSize). SetStorageClass(storageClassName). CheckedCreate(&testCtx) diff --git a/controllers/apps/transform_utils.go b/controllers/apps/transform_utils.go index ae3ff8a6ffa..03e4c1a04c3 100644 --- a/controllers/apps/transform_utils.go +++ b/controllers/apps/transform_utils.go @@ -21,23 +21,18 @@ package apps import ( "context" - "encoding/json" "reflect" "time" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/client-go/tools/record" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/apiutil" - "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1" workloads "github.com/apecloud/kubeblocks/apis/workloads/v1" "github.com/apecloud/kubeblocks/pkg/constant" - "github.com/apecloud/kubeblocks/pkg/controller/graph" - "github.com/apecloud/kubeblocks/pkg/controller/model" intctrlutil "github.com/apecloud/kubeblocks/pkg/controllerutil" ) @@ -167,58 +162,6 @@ func isVolumeClaimTemplatesEqual(a, b []appsv1.ClusterComponentVolumeClaimTempla return true } -func preserveObjects[T client.Object](ctx context.Context, cli client.Reader, graphCli model.GraphClient, dag *graph.DAG, - obj T, ml client.MatchingLabels, toPreserveKinds []client.ObjectList, finalizerName string, lastApplyAnnotationKey string) error { - if len(toPreserveKinds) == 0 { - return nil - } - - objs, err := getOwningNamespacedObjects(ctx, cli, obj.GetNamespace(), ml, toPreserveKinds) - if err != nil { - return err - } - - objSpec := obj.DeepCopyObject().(client.Object) - objSpec.SetNamespace("") - objSpec.SetName(obj.GetName()) - objSpec.SetUID(obj.GetUID()) - objSpec.SetResourceVersion("") - objSpec.SetGeneration(0) - objSpec.SetManagedFields(nil) - - b, err := json.Marshal(objSpec) - if err != nil { - return err - } - objJSON := string(b) - - for _, o := range objs { - origObj := o.DeepCopyObject().(client.Object) - controllerutil.RemoveFinalizer(o, finalizerName) - removeOwnerRefOfType(o, obj.GetObjectKind().GroupVersionKind()) - - annot := o.GetAnnotations() - if annot == nil { - annot = make(map[string]string) - } - annot[lastApplyAnnotationKey] = objJSON - o.SetAnnotations(annot) - graphCli.Update(dag, origObj, o) - } - return nil -} - -func removeOwnerRefOfType(obj client.Object, gvk schema.GroupVersionKind) { - ownerRefs := obj.GetOwnerReferences() - for i, ref := range ownerRefs { - if ref.Kind == gvk.Kind && ref.APIVersion == gvk.GroupVersion().String() { - ownerRefs = append(ownerRefs[:i], ownerRefs[i+1:]...) - break - } - } - obj.SetOwnerReferences(ownerRefs) -} - // isOwnedByComp is used to judge if the obj is owned by Component. func isOwnedByComp(obj client.Object) bool { for _, ref := range obj.GetOwnerReferences() { diff --git a/controllers/apps/transformer_cluster_deletion.go b/controllers/apps/transformer_cluster_deletion.go index 6625cf59d93..c8edd658296 100644 --- a/controllers/apps/transformer_cluster_deletion.go +++ b/controllers/apps/transformer_cluster_deletion.go @@ -62,10 +62,6 @@ func (t *clusterDeletionTransformer) Transform(ctx graph.TransformContext, dag * transCtx.EventRecorder.Eventf(cluster, corev1.EventTypeWarning, "DoNotTerminate", "spec.terminationPolicy %s is preventing deletion.", cluster.Spec.TerminationPolicy) return graph.ErrPrematureStop - case kbappsv1.Halt: - transCtx.EventRecorder.Eventf(cluster, corev1.EventTypeWarning, "Halt", - "spec.terminationPolicy %s is preventing deletion. Halt policy is deprecated is 0.9.1 and will have same meaning as DoNotTerminate.", cluster.Spec.TerminationPolicy) - return graph.ErrPrematureStop case kbappsv1.Delete: toDeleteNamespacedKinds, toDeleteNonNamespacedKinds = kindsForDelete() case kbappsv1.WipeOut: @@ -149,7 +145,7 @@ func kindsForDoNotTerminate() ([]client.ObjectList, []client.ObjectList) { return []client.ObjectList{}, []client.ObjectList{} } -func kindsForHalt() ([]client.ObjectList, []client.ObjectList) { +func kindsForDelete() ([]client.ObjectList, []client.ObjectList) { namespacedKinds, nonNamespacedKinds := kindsForDoNotTerminate() namespacedKindsPlus := []client.ObjectList{ &kbappsv1.ComponentList{}, @@ -161,11 +157,6 @@ func kindsForHalt() ([]client.ObjectList, []client.ObjectList) { return append(namespacedKinds, namespacedKindsPlus...), nonNamespacedKinds } -func kindsForDelete() ([]client.ObjectList, []client.ObjectList) { - namespacedKinds, nonNamespacedKinds := kindsForHalt() - return append(namespacedKinds, haltPreserveKinds()...), nonNamespacedKinds -} - func kindsForWipeOut() ([]client.ObjectList, []client.ObjectList) { namespacedKinds, nonNamespacedKinds := kindsForDelete() namespacedKindsPlus := []client.ObjectList{ diff --git a/controllers/apps/transformer_cluster_halt.go b/controllers/apps/transformer_cluster_halt.go deleted file mode 100644 index 2e547063cc4..00000000000 --- a/controllers/apps/transformer_cluster_halt.go +++ /dev/null @@ -1,65 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package apps - -import ( - "context" - - corev1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1" - "github.com/apecloud/kubeblocks/pkg/constant" - "github.com/apecloud/kubeblocks/pkg/controller/graph" - "github.com/apecloud/kubeblocks/pkg/controller/model" -) - -type clusterHaltTransformer struct{} - -var _ graph.Transformer = &clusterHaltTransformer{} - -func (t *clusterHaltTransformer) Transform(ctx graph.TransformContext, dag *graph.DAG) error { - transCtx, _ := ctx.(*clusterTransformContext) - cluster := transCtx.OrigCluster - if !cluster.IsDeleting() || cluster.Spec.TerminationPolicy != appsv1.Halt { - return nil - } - - var ( - graphCli, _ = transCtx.Client.(model.GraphClient) - ml = getAppInstanceML(*cluster) - toPreserveKinds = haltPreserveKinds() - ) - return preserveClusterObjects(transCtx.Context, transCtx.Client, graphCli, dag, cluster, ml, toPreserveKinds) -} - -func haltPreserveKinds() []client.ObjectList { - return []client.ObjectList{ - &corev1.PersistentVolumeClaimList{}, - &corev1.SecretList{}, - &corev1.ConfigMapList{}, - } -} - -// preserveClusterObjects preserves the objects owned by the cluster when the cluster is being deleted -func preserveClusterObjects(ctx context.Context, cli client.Reader, graphCli model.GraphClient, dag *graph.DAG, - cluster *appsv1.Cluster, ml client.MatchingLabels, toPreserveKinds []client.ObjectList) error { - return preserveObjects(ctx, cli, graphCli, dag, cluster, ml, toPreserveKinds, constant.DBClusterFinalizerName, constant.LastAppliedClusterAnnotationKey) -} diff --git a/controllers/apps/transformer_cluster_halt_recovering.go b/controllers/apps/transformer_cluster_halt_recovering.go deleted file mode 100644 index 3d35ee391c7..00000000000 --- a/controllers/apps/transformer_cluster_halt_recovering.go +++ /dev/null @@ -1,175 +0,0 @@ -/* -Copyright (C) 2022-2024 ApeCloud Co., Ltd - -This file is part of KubeBlocks project - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU Affero General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU Affero General Public License for more details. - -You should have received a copy of the GNU Affero General Public License -along with this program. If not, see . -*/ - -package apps - -import ( - "encoding/json" - "fmt" - - corev1 "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/meta" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - - appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1" - "github.com/apecloud/kubeblocks/pkg/constant" - "github.com/apecloud/kubeblocks/pkg/controller/graph" -) - -type clusterHaltRecoveryTransformer struct{} - -var _ graph.Transformer = &clusterHaltRecoveryTransformer{} - -func (t *clusterHaltRecoveryTransformer) Transform(ctx graph.TransformContext, dag *graph.DAG) error { - transCtx, _ := ctx.(*clusterTransformContext) - cluster := transCtx.Cluster - - if cluster.Status.ObservedGeneration != 0 { - // skip handling for cluster.status.observedGeneration > 0 - return nil - } - - listOptions := []client.ListOption{ - client.InNamespace(cluster.Namespace), - client.MatchingLabels{ - constant.AppInstanceLabelKey: cluster.Name, - }, - } - - pvcList := &corev1.PersistentVolumeClaimList{} - if err := transCtx.Client.List(transCtx.Context, pvcList, listOptions...); err != nil { - return newRequeueError(requeueDuration, err.Error()) - } - - if len(pvcList.Items) == 0 { - return nil - } - - emitError := func(newCondition metav1.Condition) error { - if newCondition.LastTransitionTime.IsZero() { - newCondition.LastTransitionTime = metav1.Now() - } - newCondition.Status = metav1.ConditionFalse - oldCondition := meta.FindStatusCondition(cluster.Status.Conditions, newCondition.Type) - if oldCondition == nil { - cluster.Status.Conditions = append(cluster.Status.Conditions, newCondition) - } else { - *oldCondition = newCondition - } - transCtx.EventRecorder.Event(transCtx.Cluster, corev1.EventTypeWarning, newCondition.Reason, newCondition.Message) - return graph.ErrPrematureStop - } - - // halt recovering from last applied record stored in pvc's annotation - l, ok := pvcList.Items[0].Annotations[constant.LastAppliedClusterAnnotationKey] - if !ok || l == "" { - return emitError(metav1.Condition{ - Type: appsv1.ConditionTypeHaltRecovery, - Reason: "UncleanedResources", - Message: fmt.Sprintf("found uncleaned resources, requires manual deletion, check with `kubectl -n %s get pvc,secret,cm -l %s=%s`", - cluster.Namespace, constant.AppInstanceLabelKey, cluster.Name), - }) - } - - lc := &appsv1.Cluster{} - if err := json.Unmarshal([]byte(l), lc); err != nil { - return newRequeueError(requeueDuration, err.Error()) - } - - // skip if same cluster UID - if lc.UID == cluster.UID { - return nil - } - - // check clusterDef equality - if cluster.Spec.ClusterDef != lc.Spec.ClusterDef { - return emitError(metav1.Condition{ - Type: appsv1.ConditionTypeHaltRecovery, - Reason: "HaltRecoveryFailed", - Message: fmt.Sprintf("not equal to last applied cluster.spec.clusterDef %s", lc.Spec.ClusterDef), - }) - } - - // check component len equality - if l := len(lc.Spec.ComponentSpecs); l != len(cluster.Spec.ComponentSpecs) { - return emitError(metav1.Condition{ - Type: appsv1.ConditionTypeHaltRecovery, - Reason: "HaltRecoveryFailed", - Message: fmt.Sprintf("inconsistent spec.componentSpecs counts to last applied cluster.spec.componentSpecs (len=%d)", l), - }) - } - - // check every components' equality - for _, comp := range cluster.Spec.ComponentSpecs { - found := false - for _, lastUsedComp := range lc.Spec.ComponentSpecs { - // only need to verify [name, componentDefRef, replicas] for equality - if comp.Name != lastUsedComp.Name { - continue - } - if comp.Replicas != lastUsedComp.Replicas { - return emitError(metav1.Condition{ - Type: appsv1.ConditionTypeHaltRecovery, - Reason: "HaltRecoveryFailed", - Message: fmt.Sprintf("not equal to last applied cluster.spec.componentSpecs[%s].replicas=%d", - comp.Name, lastUsedComp.Replicas), - }) - } - - // following only check resource related spec., will skip check if HaltRecoveryAllowInconsistentResAnnotKey - // annotation is specified - if cluster.Annotations[constant.HaltRecoveryAllowInconsistentResAnnotKey] == trueVal { - found = true - break - } - if !isVolumeClaimTemplatesEqual(comp.VolumeClaimTemplates, lastUsedComp.VolumeClaimTemplates) { - objJSON, _ := json.Marshal(&lastUsedComp.VolumeClaimTemplates) - return emitError(metav1.Condition{ - Type: appsv1.ConditionTypeHaltRecovery, - Reason: "HaltRecoveryFailed", - Message: fmt.Sprintf("not equal to last applied cluster.spec.componentSpecs[%s].volumeClaimTemplates=%s; add '%s=true' annotation to void this check", - comp.Name, objJSON, constant.HaltRecoveryAllowInconsistentResAnnotKey), - }) - } - - if !isResourceRequirementsEqual(comp.Resources, lastUsedComp.Resources) { - objJSON, _ := json.Marshal(&lastUsedComp.Resources) - return emitError(metav1.Condition{ - Type: appsv1.ConditionTypeHaltRecovery, - Reason: "HaltRecoveryFailed", - Message: fmt.Sprintf("not equal to last applied cluster.spec.componentSpecs[%s].resources=%s; add '%s=true' annotation to void this check", - comp.Name, objJSON, constant.HaltRecoveryAllowInconsistentResAnnotKey), - }) - } - - found = true - break - } - if !found { - return emitError(metav1.Condition{ - Type: appsv1.ConditionTypeHaltRecovery, - Reason: "HaltRecoveryFailed", - Message: fmt.Sprintf("cluster.spec.componentSpecs[%s] not found in last applied cluster", - comp.Name), - }) - } - } - return nil -} diff --git a/controllers/apps/transformer_component_deletion.go b/controllers/apps/transformer_component_deletion.go index 32071bd7b62..8c77b9a5fef 100644 --- a/controllers/apps/transformer_component_deletion.go +++ b/controllers/apps/transformer_component_deletion.go @@ -167,6 +167,9 @@ func compOwnedKinds() []client.ObjectList { return []client.ObjectList{ &workloads.InstanceSetList{}, &corev1.ServiceList{}, + &corev1.SecretList{}, + &corev1.ConfigMapList{}, + &corev1.PersistentVolumeClaimList{}, &dpv1alpha1.BackupList{}, &dpv1alpha1.RestoreList{}, &appsv1alpha1.ConfigurationList{}, @@ -175,24 +178,8 @@ func compOwnedKinds() []client.ObjectList { } } -func compOwnedPreserveKinds() []client.ObjectList { - return []client.ObjectList{ - &corev1.SecretList{}, - &corev1.ConfigMapList{}, - &corev1.PersistentVolumeClaimList{}, - } -} - -func kindsForCompDoNotTerminate() []client.ObjectList { - return []client.ObjectList{} -} - -func kindsForCompHalt() []client.ObjectList { - return append(kindsForCompDoNotTerminate(), compOwnedKinds()...) -} - func kindsForCompDelete() []client.ObjectList { - return append(kindsForCompHalt(), compOwnedPreserveKinds()...) + return compOwnedKinds() } func kindsForCompWipeOut() []client.ObjectList { diff --git a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml index be5aad680b6..19f781797f1 100644 --- a/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml +++ b/deploy/helm/crds/apps.kubeblocks.io_clusters.yaml @@ -15884,10 +15884,7 @@ spec: - `DoNotTerminate`: Prevents deletion of the Cluster. This policy ensures that all resources remain intact. - - `Halt`: Deletes Cluster resources like Pods and Services but retains Persistent Volume Claims (PVCs), - allowing for data preservation while stopping other operations. - - `Delete`: Extends the `Halt` policy by also removing PVCs, leading to a thorough cleanup while - removing all persistent data. + - `Delete`: Deletes all runtime resources belong to the Cluster. - `WipeOut`: An aggressive policy that deletes all Cluster resources, including volume snapshots and backups in external storage. This results in complete data removal and should be used cautiously, primarily in non-production environments @@ -15898,7 +15895,6 @@ spec: The `WipeOut` policy is particularly risky in production environments due to its irreversible nature. enum: - DoNotTerminate - - Halt - Delete - WipeOut type: string diff --git a/docs/developer_docs/api-reference/cluster.md b/docs/developer_docs/api-reference/cluster.md index 36714cb95fb..2d227199eb3 100644 --- a/docs/developer_docs/api-reference/cluster.md +++ b/docs/developer_docs/api-reference/cluster.md @@ -175,10 +175,7 @@ It defines how resources, data, and backups associated with a Cluster are manage Choose a policy based on the desired level of resource cleanup and data preservation:

  • DoNotTerminate: Prevents deletion of the Cluster. This policy ensures that all resources remain intact.
  • -
  • Halt: Deletes Cluster resources like Pods and Services but retains Persistent Volume Claims (PVCs), -allowing for data preservation while stopping other operations.
  • -
  • Delete: Extends the Halt policy by also removing PVCs, leading to a thorough cleanup while -removing all persistent data.
  • +
  • Delete: Deletes all runtime resources belong to the Cluster.
  • WipeOut: An aggressive policy that deletes all Cluster resources, including volume snapshots and backups in external storage. This results in complete data removal and should be used cautiously, primarily in non-production environments @@ -3187,10 +3184,7 @@ It defines how resources, data, and backups associated with a Cluster are manage Choose a policy based on the desired level of resource cleanup and data preservation:

    • DoNotTerminate: Prevents deletion of the Cluster. This policy ensures that all resources remain intact.
    • -
    • Halt: Deletes Cluster resources like Pods and Services but retains Persistent Volume Claims (PVCs), -allowing for data preservation while stopping other operations.
    • -
    • Delete: Extends the Halt policy by also removing PVCs, leading to a thorough cleanup while -removing all persistent data.
    • +
    • Delete: Deletes all runtime resources belong to the Cluster.
    • WipeOut: An aggressive policy that deletes all Cluster resources, including volume snapshots and backups in external storage. This results in complete data removal and should be used cautiously, primarily in non-production environments @@ -9701,14 +9695,11 @@ string

      "Delete"

      -

      Delete is based on Halt and deletes PVCs.

      +

      Delete will delete all runtime resources belong to the cluster.

      "DoNotTerminate"

      DoNotTerminate will block delete operation.

      -

      "Halt"

      -

      Halt will delete workload resources such as statefulset, deployment workloads but keep PVCs.

      -

      "WipeOut"

      WipeOut is based on Delete and wipe out all volume snapshots and snapshot data from backup storage location.

      diff --git a/pkg/constant/annotations.go b/pkg/constant/annotations.go index ad40dd9679f..c2dd7c352cc 100644 --- a/pkg/constant/annotations.go +++ b/pkg/constant/annotations.go @@ -25,22 +25,20 @@ const ( // annotations defined by KubeBlocks const ( - ClusterSnapshotAnnotationKey = "kubeblocks.io/cluster-snapshot" // ClusterSnapshotAnnotationKey saves the snapshot of cluster. - EncryptedSystemAccountsAnnotationKey = "kubeblocks.io/encrypted-system-accounts" // EncryptedSystemAccountsAnnotationKey saves the encrypted system accounts. - OpsRequestAnnotationKey = "kubeblocks.io/ops-request" // OpsRequestAnnotationKey OpsRequest annotation key in Cluster - ReconcileAnnotationKey = "kubeblocks.io/reconcile" // ReconcileAnnotationKey Notify k8s object to reconcile - RestartAnnotationKey = "kubeblocks.io/restart" // RestartAnnotationKey the annotation which notices the StatefulSet/DeploySet to restart - RestoreFromBackupAnnotationKey = "kubeblocks.io/restore-from-backup" - RestoreDoneAnnotationKey = "kubeblocks.io/restore-done" - BackupSourceTargetAnnotationKey = "kubeblocks.io/backup-source-target" // RestoreFromBackupAnnotationKey specifies the component to recover from the backup. - BackupPolicyTemplateAnnotationKey = "apps.kubeblocks.io/backup-policy-template" - LastAppliedClusterAnnotationKey = "apps.kubeblocks.io/last-applied-cluster" - PVLastClaimPolicyAnnotationKey = "apps.kubeblocks.io/pv-last-claim-policy" - HaltRecoveryAllowInconsistentResAnnotKey = "clusters.apps.kubeblocks.io/allow-inconsistent-resource" - KubeBlocksGenerationKey = "kubeblocks.io/generation" - KBAppClusterUIDKey = "apps.kubeblocks.io/cluster-uid" - LastRoleSnapshotVersionAnnotationKey = "apps.kubeblocks.io/last-role-snapshot-version" - ComponentScaleInAnnotationKey = "apps.kubeblocks.io/component-scale-in" // ComponentScaleInAnnotationKey specifies whether the component is scaled in + ClusterSnapshotAnnotationKey = "kubeblocks.io/cluster-snapshot" // ClusterSnapshotAnnotationKey saves the snapshot of cluster. + EncryptedSystemAccountsAnnotationKey = "kubeblocks.io/encrypted-system-accounts" // EncryptedSystemAccountsAnnotationKey saves the encrypted system accounts. + OpsRequestAnnotationKey = "kubeblocks.io/ops-request" // OpsRequestAnnotationKey OpsRequest annotation key in Cluster + ReconcileAnnotationKey = "kubeblocks.io/reconcile" // ReconcileAnnotationKey Notify k8s object to reconcile + RestartAnnotationKey = "kubeblocks.io/restart" // RestartAnnotationKey the annotation which notices the StatefulSet/DeploySet to restart + RestoreFromBackupAnnotationKey = "kubeblocks.io/restore-from-backup" + RestoreDoneAnnotationKey = "kubeblocks.io/restore-done" + BackupSourceTargetAnnotationKey = "kubeblocks.io/backup-source-target" // RestoreFromBackupAnnotationKey specifies the component to recover from the backup. + BackupPolicyTemplateAnnotationKey = "apps.kubeblocks.io/backup-policy-template" + PVLastClaimPolicyAnnotationKey = "apps.kubeblocks.io/pv-last-claim-policy" + KubeBlocksGenerationKey = "kubeblocks.io/generation" + KBAppClusterUIDKey = "apps.kubeblocks.io/cluster-uid" + LastRoleSnapshotVersionAnnotationKey = "apps.kubeblocks.io/last-role-snapshot-version" + ComponentScaleInAnnotationKey = "apps.kubeblocks.io/component-scale-in" // ComponentScaleInAnnotationKey specifies whether the component is scaled in // SkipImmutableCheckAnnotationKey specifies to skip the mutation check for the object. // The mutation check is only applied to the fields that are declared as immutable. diff --git a/pkg/controller/plan/restore.go b/pkg/controller/plan/restore.go index d9008c9732a..37b22ecb058 100644 --- a/pkg/controller/plan/restore.go +++ b/pkg/controller/plan/restore.go @@ -164,16 +164,6 @@ func (r *RestoreManager) BuildPrepareDataRestore(comp *component.SynthesizedComp if targetVolumes == nil { return nil, nil } - getClusterJSON := func() string { - clusterSpec := r.Cluster.DeepCopy() - clusterSpec.ObjectMeta = metav1.ObjectMeta{ - Name: clusterSpec.GetName(), - UID: clusterSpec.GetUID(), - } - clusterSpec.Status = appsv1.ClusterStatus{} - b, _ := json.Marshal(*clusterSpec) - return string(b) - } var templates []dpv1alpha1.RestoreVolumeClaim pvcLabels := constant.GetCompLabels(r.Cluster.Name, comp.Name) @@ -190,10 +180,6 @@ func (r *RestoreManager) BuildPrepareDataRestore(comp *component.SynthesizedComp ObjectMeta: metav1.ObjectMeta{ Name: name, Labels: pvcLabels, - Annotations: map[string]string{ - // satisfy the detection of transformer_halt_recovering. - constant.LastAppliedClusterAnnotationKey: getClusterJSON(), - }, }, } // build pvc labels