diff --git a/controllers/apps/cluster_controller_test.go b/controllers/apps/cluster_controller_test.go index 2b63c0bcb3d..faa20ae54af 100644 --- a/controllers/apps/cluster_controller_test.go +++ b/controllers/apps/cluster_controller_test.go @@ -1062,7 +1062,7 @@ var _ = Describe("Cluster Controller", func() { // TODO(component) } - deleteClusterWithBackup := func(terminationPolicy appsv1alpha1.TerminationPolicyType, backupRetainPolicy string) { + deleteClusterWithBackup := func(terminationPolicy appsv1alpha1.TerminationPolicyType) { By("mocking a retained backup") backupPolicyName := "test-backup-policy" backupName := "test-backup" @@ -1071,9 +1071,8 @@ var _ = Describe("Cluster Controller", func() { SetBackupPolicyName(backupPolicyName). SetBackupMethod(backupMethod). SetLabels(map[string]string{ - constant.AppManagedByLabelKey: constant.AppName, - constant.AppInstanceLabelKey: clusterObj.Name, - constant.BackupProtectionLabelKey: backupRetainPolicy, + constant.AppManagedByLabelKey: constant.AppName, + constant.AppInstanceLabelKey: clusterObj.Name, }). WithRandomName(). Create(&testCtx).GetObject() @@ -1086,8 +1085,8 @@ var _ = Describe("Cluster Controller", func() { By("wait for the cluster to terminate") Eventually(testapps.CheckObjExists(&testCtx, clusterKey, &appsv1alpha1.Cluster{}, false)).Should(Succeed()) - By(fmt.Sprintf("checking the backup with TerminationPolicyType=%s", terminationPolicy)) - if terminationPolicy == appsv1alpha1.WipeOut && backupRetainPolicy == constant.BackupDelete { + By("checking the backup") + if terminationPolicy == appsv1alpha1.WipeOut { Eventually(testapps.CheckObjExists(&testCtx, backupKey, &dpv1alpha1.Backup{}, false)).Should(Succeed()) } else { Consistently(testapps.CheckObjExists(&testCtx, backupKey, &dpv1alpha1.Backup{}, true)).Should(Succeed()) @@ -1099,7 +1098,7 @@ var _ = Describe("Cluster Controller", func() { Client: testCtx.Cli, } var namespacedKinds, clusteredKinds []client.ObjectList - if terminationPolicy == appsv1alpha1.WipeOut && backupRetainPolicy == constant.BackupDelete { + if terminationPolicy == appsv1alpha1.WipeOut { namespacedKinds, clusteredKinds = kindsForWipeOut() } else { namespacedKinds, clusteredKinds = kindsForDelete() @@ -1112,12 +1111,12 @@ var _ = Describe("Cluster Controller", func() { testDeleteClusterWithDelete := func(createObj func(appsv1alpha1.TerminationPolicyType)) { createObj(appsv1alpha1.Delete) - deleteClusterWithBackup(appsv1alpha1.Delete, constant.BackupRetain) + deleteClusterWithBackup(appsv1alpha1.Delete) } - testDeleteClusterWithWipeOut := func(createObj func(appsv1alpha1.TerminationPolicyType), backupRetainPolicy string) { + testDeleteClusterWithWipeOut := func(createObj func(appsv1alpha1.TerminationPolicyType)) { createObj(appsv1alpha1.WipeOut) - deleteClusterWithBackup(appsv1alpha1.WipeOut, backupRetainPolicy) + deleteClusterWithBackup(appsv1alpha1.WipeOut) } Context("cluster provisioning", func() { @@ -1230,12 +1229,8 @@ var _ = Describe("Cluster Controller", func() { testDeleteClusterWithDelete(createObj) }) - It("delete cluster with terminationPolicy=WipeOut and backupRetainPolicy=Delete", func() { - testDeleteClusterWithWipeOut(createObj, constant.BackupDelete) - }) - - It("delete cluster with terminationPolicy=WipeOut and backupRetainPolicy=Retain", func() { - testDeleteClusterWithWipeOut(createObj, constant.BackupRetain) + It("delete cluster with terminationPolicy=WipeOut", func() { + testDeleteClusterWithWipeOut(createObj) }) } }) diff --git a/controllers/apps/operations/backup.go b/controllers/apps/operations/backup.go index 86979f6311b..1f5aec3aed2 100644 --- a/controllers/apps/operations/backup.go +++ b/controllers/apps/operations/backup.go @@ -212,9 +212,8 @@ func getDefaultBackupPolicy(reqCtx intctrlutil.RequestCtx, cli client.Client, cl func getBackupLabels(cluster, request string) map[string]string { return map[string]string{ - constant.AppInstanceLabelKey: cluster, - constant.BackupProtectionLabelKey: constant.BackupRetain, - constant.OpsRequestNameLabelKey: request, - constant.OpsRequestTypeLabelKey: string(appsv1alpha1.BackupType), + constant.AppInstanceLabelKey: cluster, + constant.OpsRequestNameLabelKey: request, + constant.OpsRequestTypeLabelKey: string(appsv1alpha1.BackupType), } } diff --git a/controllers/apps/transform_utils.go b/controllers/apps/transform_utils.go index 0de922f948e..0be779b9ca3 100644 --- a/controllers/apps/transform_utils.go +++ b/controllers/apps/transform_utils.go @@ -34,11 +34,13 @@ import ( "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1" + dpv1alpha1 "github.com/apecloud/kubeblocks/apis/dataprotection/v1alpha1" workloads "github.com/apecloud/kubeblocks/apis/workloads/v1alpha1" "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" + dptypes "github.com/apecloud/kubeblocks/pkg/dataprotection/types" ) func newRequeueError(after time.Duration, reason string) error { @@ -65,6 +67,32 @@ func getAppInstanceML(cluster appsv1alpha1.Cluster) client.MatchingLabels { } } +func getFailedBackups(ctx context.Context, + cli client.Reader, + namespace string, + labels client.MatchingLabels, + owningNamespacedObjects owningObjects) error { + backupList := &dpv1alpha1.BackupList{} + if err := cli.List(ctx, backupList, client.InNamespace(namespace), labels); err != nil { + return err + } + + for i := range backupList.Items { + backup := &backupList.Items[i] + if backup.Status.Phase != dpv1alpha1.BackupPhaseFailed { + continue + } + if backup.Labels[dptypes.BackupTypeLabelKey] != string(dpv1alpha1.BackupTypeContinuous) { + gvr, err := getGVKName(backup, rscheme) + if err != nil { + return err + } + owningNamespacedObjects[*gvr] = backup + } + } + return nil +} + func getOwningNamespacedObjects(ctx context.Context, cli client.Reader, namespace string, diff --git a/controllers/apps/transformer_cluster_deletion.go b/controllers/apps/transformer_cluster_deletion.go index b728aedf795..219393aa933 100644 --- a/controllers/apps/transformer_cluster_deletion.go +++ b/controllers/apps/transformer_cluster_deletion.go @@ -39,6 +39,7 @@ import ( "github.com/apecloud/kubeblocks/pkg/controller/component" "github.com/apecloud/kubeblocks/pkg/controller/graph" "github.com/apecloud/kubeblocks/pkg/controller/model" + dptypes "github.com/apecloud/kubeblocks/pkg/dataprotection/types" ) // clusterDeletionTransformer handles cluster deletion @@ -88,9 +89,12 @@ func (t *clusterDeletionTransformer) Transform(ctx graph.TransformContext, dag * toDeleteObjs := func(objs owningObjects) []client.Object { var delObjs []client.Object for _, obj := range objs { - // retain backup for data protection even if the cluster is wiped out. - if strings.EqualFold(obj.GetLabels()[constant.BackupProtectionLabelKey], constant.BackupRetain) { - continue + if obj.GetObjectKind().GroupVersionKind().Kind == dptypes.BackupKind { + backupObj := obj.(*dpv1alpha1.Backup) + // retain backup for data protection even if the cluster is wiped out. + if backupObj.Spec.DeletionPolicy == dpv1alpha1.BackupDeletionPolicyRetain { + continue + } } delObjs = append(delObjs, obj) } @@ -105,6 +109,11 @@ func (t *clusterDeletionTransformer) Transform(ctx graph.TransformContext, dag * return err } } + if cluster.Spec.TerminationPolicy != appsv1alpha1.WipeOut { + if err = getFailedBackups(transCtx.Context, transCtx.Client, cluster.Namespace, ml, namespacedObjs); err != nil { + return err + } + } delObjs := toDeleteObjs(namespacedObjs) // add non-namespaced objects deletion vertex diff --git a/pkg/constant/const.go b/pkg/constant/const.go index d0d189ad404..a0dbca7ae24 100644 --- a/pkg/constant/const.go +++ b/pkg/constant/const.go @@ -96,8 +96,7 @@ const ( ZoneLabelKey = "topology.kubernetes.io/zone" // kubeblocks.io labels - BackupProtectionLabelKey = "kubeblocks.io/backup-protection" // BackupProtectionLabelKey Backup delete protection policy label - RoleLabelKey = "kubeblocks.io/role" // RoleLabelKey consensusSet and replicationSet role label key + RoleLabelKey = "kubeblocks.io/role" // RoleLabelKey consensusSet and replicationSet role label key AccessModeLabelKey = "workloads.kubeblocks.io/access-mode" ReadyWithoutPrimaryKey = "kubeblocks.io/ready-without-primary" VolumeTypeLabelKey = "kubeblocks.io/volume-type" @@ -231,17 +230,6 @@ const ( DaemonSetKind = "DaemonSet" ) -const ( - // BackupRetain always retained, unless manually deleted by the user - BackupRetain = "Retain" - - // BackupRetainUntilExpired retains backup till it expires - BackupRetainUntilExpired = "RetainUntilExpired" - - // BackupDelete (default) deletes backup immediately when cluster's terminationPolicy is WipeOut - BackupDelete = "Delete" -) - const ( // Container port name LorryHTTPPortName = "lorry-http-port"