Skip to content

Commit d05b1c0

Browse files
yipeng1030wangyelei
authored andcommitted
chore: cluster delete support force (#582)
Co-authored-by: yipeng1030 <yipeng1030@users.noreply.github.com> (cherry picked from commit a472c89)
1 parent 9601ec6 commit d05b1c0

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

docs/user_docs/cli/kbcli_cluster_delete.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@ kbcli cluster delete NAME [flags]
1313
```
1414
# delete a cluster named mycluster
1515
kbcli cluster delete mycluster
16+
1617
# delete a cluster by label selector
1718
kbcli cluster delete --selector clusterdefinition.kubeblocks.io/name=apecloud-mysql
19+
20+
# delete a cluster named mycluster forcedly
21+
kbcli cluster delete mycluster --force
1822
```
1923

2024
### Options

pkg/cmd/cluster/delete.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@ import (
2929
cmdutil "k8s.io/kubectl/pkg/cmd/util"
3030
"k8s.io/kubectl/pkg/util/templates"
3131

32+
appsv1 "github.com/apecloud/kubeblocks/apis/apps/v1"
3233
appsv1alpha1 "github.com/apecloud/kubeblocks/apis/apps/v1alpha1"
34+
"github.com/apecloud/kubeblocks/pkg/constant"
3335

3436
"github.com/apecloud/kbcli/pkg/action"
37+
"github.com/apecloud/kbcli/pkg/printer"
3538
"github.com/apecloud/kbcli/pkg/types"
3639
"github.com/apecloud/kbcli/pkg/util"
3740
)
@@ -40,8 +43,12 @@ var (
4043
deleteExample = templates.Examples(`
4144
# delete a cluster named mycluster
4245
kbcli cluster delete mycluster
46+
4347
# delete a cluster by label selector
4448
kbcli cluster delete --selector clusterdefinition.kubeblocks.io/name=apecloud-mysql
49+
50+
# delete a cluster named mycluster forcedly
51+
kbcli cluster delete mycluster --force
4552
`)
4653
)
4754

@@ -80,9 +87,25 @@ func clusterPreDeleteHook(o *action.DeleteOptions, object runtime.Object) error
8087
if err != nil {
8188
return err
8289
}
83-
if cluster.Spec.TerminationPolicy == appsv1alpha1.DoNotTerminate {
90+
if cluster.Spec.TerminationPolicy == appsv1.DoNotTerminate {
8491
return fmt.Errorf("cluster %s is protected by termination policy %s, skip deleting", cluster.Name, appsv1alpha1.DoNotTerminate)
8592
}
93+
94+
if o.Force {
95+
fmt.Fprintf(o.Out, printer.BoldRed("WARNING: Using --force may lead to potential data loss or residual dirty data if the cluster depends on other clusters.\n"))
96+
components := util.GetComponentsOrShards(cluster)
97+
for _, componentName := range components {
98+
dynamicClient, err := o.Factory.DynamicClient()
99+
if err != nil {
100+
return err
101+
}
102+
err = util.AddAnnotationToComponentOrShard(dynamicClient, constant.GenerateClusterComponentName(cluster.Name, componentName), cluster.Namespace, constant.SkipPreTerminateAnnotationKey, "true")
103+
if err != nil {
104+
return fmt.Errorf("failed to add annotation to component %s: %v", componentName, err)
105+
}
106+
}
107+
}
108+
86109
return nil
87110
}
88111

@@ -96,12 +119,12 @@ func clusterPostDeleteHook(o *action.DeleteOptions, object runtime.Object) error
96119
return nil
97120
}
98121

99-
func getClusterFromObject(object runtime.Object) (*appsv1alpha1.Cluster, error) {
100-
if object.GetObjectKind().GroupVersionKind().Kind != appsv1alpha1.ClusterKind {
122+
func getClusterFromObject(object runtime.Object) (*appsv1.Cluster, error) {
123+
if object.GetObjectKind().GroupVersionKind().Kind != appsv1.ClusterKind {
101124
return nil, fmt.Errorf("object %s is not of kind %s", object.GetObjectKind().GroupVersionKind().Kind, appsv1alpha1.ClusterKind)
102125
}
103126
u := object.(*unstructured.Unstructured)
104-
cluster := &appsv1alpha1.Cluster{}
127+
cluster := &appsv1.Cluster{}
105128
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, cluster); err != nil {
106129
return nil, err
107130
}

pkg/util/util.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,3 +1287,38 @@ func SetHelmOwner(dynamicClient dynamic.Interface, gvr schema.GroupVersionResour
12871287
}
12881288
return nil
12891289
}
1290+
1291+
// AddAnnotationToComponentOrShard adds a specific annotation to a component.
1292+
func AddAnnotationToComponentOrShard(dynamicClient dynamic.Interface, componentName, namespace, annotationKey, annotationValue string) error {
1293+
gvr := types.ComponentGVR()
1294+
resourceClient := dynamicClient.Resource(gvr).Namespace(namespace)
1295+
componentObj, err := resourceClient.Get(context.Background(), componentName, metav1.GetOptions{})
1296+
if err != nil {
1297+
return fmt.Errorf("failed to get component %s: %v", componentName, err)
1298+
}
1299+
1300+
annotations := componentObj.GetAnnotations()
1301+
if annotations == nil {
1302+
annotations = make(map[string]string)
1303+
}
1304+
annotations[annotationKey] = annotationValue
1305+
componentObj.SetAnnotations(annotations)
1306+
1307+
_, err = resourceClient.Update(context.Background(), componentObj, metav1.UpdateOptions{})
1308+
if err != nil {
1309+
return fmt.Errorf("failed to update component %s with annotation %s: %v", componentName, annotationKey, err)
1310+
}
1311+
1312+
return nil
1313+
}
1314+
1315+
func GetComponentsOrShards(cluster *kbappsv1.Cluster) []string {
1316+
var components []string
1317+
for _, component := range cluster.Spec.ComponentSpecs {
1318+
components = append(components, component.Name)
1319+
}
1320+
for _, sharding := range cluster.Spec.Shardings {
1321+
components = append(components, sharding.Name)
1322+
}
1323+
return components
1324+
}

0 commit comments

Comments
 (0)