Skip to content

Commit

Permalink
Enhanced forced deletion on karmadactl unjoin
Browse files Browse the repository at this point in the history
Signed-off-by: zhzhuang-zju <m17799853869@163.com>
  • Loading branch information
zhzhuang-zju committed Oct 31, 2024
1 parent 9c0bd72 commit 1a0575b
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 10 deletions.
91 changes: 88 additions & 3 deletions pkg/karmadactl/unjoin/unjoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,18 @@ limitations under the License.
package unjoin

import (
"context"
"fmt"
"time"

"github.com/spf13/cobra"
"github.com/spf13/pflag"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kubeclient "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/klog/v2"
"k8s.io/kubectl/pkg/util/templates"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"

karmadaclientset "github.com/karmada-io/karmada/pkg/generated/clientset/versioned"
"github.com/karmada-io/karmada/pkg/karmadactl/options"
Expand Down Expand Up @@ -147,7 +150,7 @@ func (j *CommandUnjoinOption) AddFlags(flags *pflag.FlagSet) {
flags.StringVar(&j.ClusterKubeConfig, "cluster-kubeconfig", "",
"Path of the cluster's kubeconfig.")
flags.BoolVar(&j.forceDeletion, "force", false,
"Delete cluster and secret resources even if resources in the cluster targeted for unjoin are not removed successfully.")
"If true, when the unjoin process fails due to a timeout, force unjoin the member cluster by removing the finalizer from the related work, namespace, and cluster resources. Note that forcing the unjoin of a member cluster may result in residual resources and requires confirmation.")
flags.DurationVar(&j.Wait, "wait", 60*time.Second, "wait for the unjoin command execution process(default 60s), if there is no success after this time, timeout will be returned.")
flags.BoolVar(&j.DryRun, "dry-run", false, "Run the command in dry-run mode, without making any server requests.")
}
Expand Down Expand Up @@ -181,11 +184,11 @@ func (j *CommandUnjoinOption) Run(f cmdutil.Factory) error {
// RunUnJoinCluster unJoin the cluster from karmada.
func (j *CommandUnjoinOption) RunUnJoinCluster(controlPlaneRestConfig, clusterConfig *rest.Config) error {
controlPlaneKarmadaClient := karmadaclientset.NewForConfigOrDie(controlPlaneRestConfig)
controlPlaneKubeClient := kubeclient.NewForConfigOrDie(controlPlaneRestConfig)

// delete the cluster object in host cluster that associates the unjoining cluster
err := cmdutil.DeleteClusterObject(controlPlaneKarmadaClient, j.ClusterName, j.Wait, j.DryRun)
err := j.deleteClusterObject(controlPlaneKubeClient, controlPlaneKarmadaClient)
if err != nil {
klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", j.ClusterName, err)
return err
}

Expand Down Expand Up @@ -221,6 +224,33 @@ func (j *CommandUnjoinOption) RunUnJoinCluster(controlPlaneRestConfig, clusterCo
return nil
}

func (j *CommandUnjoinOption) deleteClusterObject(controlPlaneKubeClient *kubeclient.Clientset, controlPlaneKarmadaClient *karmadaclientset.Clientset) error {
isTimeout, err := cmdutil.DeleteClusterObject(controlPlaneKarmadaClient, j.ClusterName, j.Wait, j.DryRun)
if j.forceDeletion && err != nil && isTimeout {
klog.Infof("Start forced deletion. cluster name: %s", j.ClusterName)
executionSpaceName := names.GenerateExecutionSpaceName(j.ClusterName)
err = removeWorkFinalizer(executionSpaceName, controlPlaneKarmadaClient)
if err != nil {
klog.Errorf("Force deletion. Failed to remove the finalizer of Work, error: %v", err)
}

err = removeExecutionSpaceFinalizer(executionSpaceName, controlPlaneKubeClient)
if err != nil {
klog.Errorf("Force deletion. Failed to remove the finalizer of Namespace(%s), error: %v", executionSpaceName, err)
}

err = removeClusterFinalizer(j.ClusterName, controlPlaneKarmadaClient)
if err != nil {
klog.Errorf("Force deletion. Failed to remove the finalizer of Cluster(%s), error: %v", j.ClusterName, err)
}

klog.Infof("Forced deletion is complete.")
return nil
}

return err
}

// deleteRBACResources deletes the cluster role, cluster rolebindings from the unjoining cluster.
func deleteRBACResources(clusterKubeClient kubeclient.Interface, unjoiningClusterName string, forceDeletion, dryRun bool) error {
if dryRun {
Expand Down Expand Up @@ -284,3 +314,58 @@ func deleteNamespaceFromUnjoinCluster(clusterKubeClient kubeclient.Interface, na

return nil
}

// removeWorkFinalizer removes the finalizer of works from the executionSpace
func removeWorkFinalizer(executionSpaceName string, controlPlaneKarmadaClient *karmadaclientset.Clientset) error {
list, err := controlPlaneKarmadaClient.WorkV1alpha1().Works(executionSpaceName).List(context.TODO(), metav1.ListOptions{})
if err != nil {
return fmt.Errorf("failed to list work in executionSpace %s", executionSpaceName)
}

for i := range list.Items {
work := &list.Items[i]
if !controllerutil.ContainsFinalizer(work, util.ExecutionControllerFinalizer) {
continue
}
controllerutil.RemoveFinalizer(work, util.ExecutionControllerFinalizer)
_, err = controlPlaneKarmadaClient.WorkV1alpha1().Works(executionSpaceName).Update(context.TODO(), work, metav1.UpdateOptions{})
if err != nil {
return fmt.Errorf("failed to remove the finalizer of work(%s/%s)", executionSpaceName, work.GetName())
}
}
return nil
}

// removeExecutionSpaceFinalizer removes the finalizer of executionSpace
func removeExecutionSpaceFinalizer(executionSpaceName string, controlPlaneKubeClient *kubeclient.Clientset) error {
executionSpace, err := controlPlaneKubeClient.CoreV1().Namespaces().Get(context.TODO(), executionSpaceName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("failed to get Namespace(%s)", executionSpaceName)
}

if !controllerutil.ContainsFinalizer(executionSpace, "kubernetes") {
return nil
}

controllerutil.RemoveFinalizer(executionSpace, "kubernetes")
_, err = controlPlaneKubeClient.CoreV1().Namespaces().Update(context.TODO(), executionSpace, metav1.UpdateOptions{})

return err
}

// removeClusterFinalizer removes the finalizer of cluster object
func removeClusterFinalizer(clusterName string, controlPlaneKarmadaClient *karmadaclientset.Clientset) error {
cluster, err := controlPlaneKarmadaClient.ClusterV1alpha1().Clusters().Get(context.TODO(), clusterName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("failed to get Cluster(%s)", clusterName)
}

if !controllerutil.ContainsFinalizer(cluster, util.ClusterControllerFinalizer) {
return nil
}

controllerutil.RemoveFinalizer(cluster, util.ClusterControllerFinalizer)
_, err = controlPlaneKarmadaClient.ClusterV1alpha1().Clusters().Update(context.TODO(), cluster, metav1.UpdateOptions{})

return err
}
2 changes: 1 addition & 1 deletion pkg/karmadactl/unregister/unregister.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ func (j *CommandUnregisterOption) RunUnregisterCluster() error {
}

// 1. delete the cluster object from the Karmada control plane
if err := cmdutil.DeleteClusterObject(j.ControlPlaneClient, j.ClusterName, j.Wait, j.DryRun); err != nil {
if _, err := cmdutil.DeleteClusterObject(j.ControlPlaneClient, j.ClusterName, j.Wait, j.DryRun); err != nil {
klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", j.ClusterName, err)
return err
}
Expand Down
12 changes: 6 additions & 6 deletions pkg/karmadactl/util/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,18 @@ import (

// DeleteClusterObject deletes the cluster object from the Karmada control plane.
func DeleteClusterObject(controlPlaneKarmadaClient karmadaclientset.Interface, clusterName string,
timeout time.Duration, dryRun bool) error {
timeout time.Duration, dryRun bool) (isTimeOut bool, errs error) {
if dryRun {
return nil
return false, nil
}

err := controlPlaneKarmadaClient.ClusterV1alpha1().Clusters().Delete(context.TODO(), clusterName, metav1.DeleteOptions{})
if apierrors.IsNotFound(err) {
return fmt.Errorf("no cluster object %s found in karmada control Plane", clusterName)
return false, fmt.Errorf("no cluster object %s found in karmada control Plane", clusterName)
}
if err != nil {
klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", clusterName, err)
return err
return false, err
}

// make sure the given cluster object has been deleted
Expand All @@ -60,8 +60,8 @@ func DeleteClusterObject(controlPlaneKarmadaClient karmadaclientset.Interface, c
})
if err != nil {
klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", clusterName, err)
return err
return true, err
}

return nil
return false, nil
}

0 comments on commit 1a0575b

Please sign in to comment.