Skip to content

Commit

Permalink
chore: support to delete failed backups when deleting cluster (#8433)
Browse files Browse the repository at this point in the history
  • Loading branch information
wangyelei authored Nov 11, 2024
1 parent 8dfc740 commit cc6c82d
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 36 deletions.
27 changes: 11 additions & 16 deletions controllers/apps/cluster_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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()
Expand All @@ -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())
Expand All @@ -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()
Expand All @@ -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() {
Expand Down Expand Up @@ -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)
})
}
})
Expand Down
7 changes: 3 additions & 4 deletions controllers/apps/operations/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}
28 changes: 28 additions & 0 deletions controllers/apps/transform_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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,
Expand Down
15 changes: 12 additions & 3 deletions controllers/apps/transformer_cluster_deletion.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand All @@ -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
Expand Down
14 changes: 1 addition & 13 deletions pkg/constant/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down

0 comments on commit cc6c82d

Please sign in to comment.