From f751f9fe0df5040fb445a26798acfd579170600a Mon Sep 17 00:00:00 2001 From: zhzhuang-zju Date: Thu, 6 Feb 2025 10:27:49 +0800 Subject: [PATCH] Restrict the cluster sync mode for the unjoin and unregister command Signed-off-by: zhzhuang-zju --- pkg/karmadactl/unjoin/unjoin.go | 18 +++++++++- pkg/karmadactl/unjoin/unjoin_test.go | 38 ++++++++++++++++++++ pkg/karmadactl/unregister/unregister.go | 15 +++++++- pkg/karmadactl/unregister/unregister_test.go | 16 +++++++-- 4 files changed, 83 insertions(+), 4 deletions(-) diff --git a/pkg/karmadactl/unjoin/unjoin.go b/pkg/karmadactl/unjoin/unjoin.go index 7876c871fa07..d808d9c57b7a 100644 --- a/pkg/karmadactl/unjoin/unjoin.go +++ b/pkg/karmadactl/unjoin/unjoin.go @@ -17,17 +17,21 @@ limitations under the License. package unjoin import ( + "context" "errors" "fmt" "time" "github.com/spf13/cobra" "github.com/spf13/pflag" + apierrors "k8s.io/apimachinery/pkg/api/errors" + 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" + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" karmadaclientset "github.com/karmada-io/karmada/pkg/generated/clientset/versioned" "github.com/karmada-io/karmada/pkg/karmadactl/options" cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util" @@ -194,8 +198,20 @@ func (j *CommandUnjoinOption) RunUnJoinCluster(controlPlaneRestConfig, clusterCo controlPlaneKarmadaClient := controlPlaneKarmadaClientBuilder(controlPlaneRestConfig) controlPlaneKubeClient := controlPlaneKubeClientBuilder(controlPlaneRestConfig) + target, err := controlPlaneKarmadaClient.ClusterV1alpha1().Clusters().Get(context.TODO(), j.ClusterName, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + return fmt.Errorf("no cluster object %s found in karmada control Plane", j.ClusterName) + } + if err != nil { + klog.Errorf("Failed to get cluster object. cluster name: %s, error: %v", j.ClusterName, err) + return err + } + if target.Spec.SyncMode == clusterv1alpha1.Pull { + return fmt.Errorf("cluster %s is a %s mode member cluster, please use command `unregister` if you want to continue unregistering the cluster", j.ClusterName, target.Spec.SyncMode) + } + // delete the cluster object in host cluster that associates the unjoining cluster - err := cmdutil.DeleteClusterObject(controlPlaneKubeClient, controlPlaneKarmadaClient, j.ClusterName, j.Wait, j.DryRun, j.forceDeletion) + err = cmdutil.DeleteClusterObject(controlPlaneKubeClient, controlPlaneKarmadaClient, j.ClusterName, j.Wait, j.DryRun, j.forceDeletion) if err != nil { klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", j.ClusterName, err) return err diff --git a/pkg/karmadactl/unjoin/unjoin_test.go b/pkg/karmadactl/unjoin/unjoin_test.go index fb4d315c8d1e..91cb31d96ef0 100644 --- a/pkg/karmadactl/unjoin/unjoin_test.go +++ b/pkg/karmadactl/unjoin/unjoin_test.go @@ -111,6 +111,34 @@ func TestRunUnJoinCluster(t *testing.T) { wantErr bool errMsg string }{ + { + name: "RunUnJoinCluster_DeleteClusterObject_PullModeMemberCluster", + unjoinOpts: &CommandUnjoinOption{ClusterName: "member1"}, + controlPlaneRestConfig: &rest.Config{}, + clusterConfig: &rest.Config{}, + karmadaClient: fakekarmadaclient.NewSimpleClientset(), + prep: func(_ kubeclient.Interface, _ kubeclient.Interface, karmadaClient karmadaclientset.Interface, _ *CommandUnjoinOption) error { + karmadaClient.(*fakekarmadaclient.Clientset).Fake.PrependReactor("get", "clusters", func(coretesting.Action) (bool, runtime.Object, error) { + return true, &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "member1", + }, + Spec: clusterv1alpha1.ClusterSpec{ + SyncMode: clusterv1alpha1.Pull, + }, + }, nil + }) + controlPlaneKarmadaClientBuilder = func(*rest.Config) karmadaclientset.Interface { + return karmadaClient + } + return nil + }, + verify: func(kubeclient.Interface, kubeclient.Interface, karmadaclientset.Interface, *CommandUnjoinOption) error { + return nil + }, + wantErr: true, + errMsg: "cluster member1 is a Pull mode member cluster, please use command `unregister` if you want to continue unregistering the cluster", + }, { name: "RunUnJoinCluster_DeleteClusterObject_FailedToDeleteClusterObject", unjoinOpts: &CommandUnjoinOption{ClusterName: "member1"}, @@ -118,6 +146,16 @@ func TestRunUnJoinCluster(t *testing.T) { clusterConfig: &rest.Config{}, karmadaClient: fakekarmadaclient.NewSimpleClientset(), prep: func(_ kubeclient.Interface, _ kubeclient.Interface, karmadaClient karmadaclientset.Interface, _ *CommandUnjoinOption) error { + karmadaClient.(*fakekarmadaclient.Clientset).Fake.PrependReactor("get", "clusters", func(coretesting.Action) (bool, runtime.Object, error) { + return true, &clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: "member1", + }, + Spec: clusterv1alpha1.ClusterSpec{ + SyncMode: clusterv1alpha1.Push, + }, + }, nil + }) karmadaClient.(*fakekarmadaclient.Clientset).Fake.PrependReactor("delete", "clusters", func(coretesting.Action) (bool, runtime.Object, error) { return true, nil, errors.New("unexpected error: encountered a network issue while deleting the clusters") }) diff --git a/pkg/karmadactl/unregister/unregister.go b/pkg/karmadactl/unregister/unregister.go index 353bb8df3b6d..5fd6f04c0b3c 100644 --- a/pkg/karmadactl/unregister/unregister.go +++ b/pkg/karmadactl/unregister/unregister.go @@ -35,6 +35,7 @@ import ( "k8s.io/klog/v2" "k8s.io/kubectl/pkg/util/templates" + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" "github.com/karmada-io/karmada/pkg/apis/cluster/validation" karmadaclientset "github.com/karmada-io/karmada/pkg/generated/clientset/versioned" "github.com/karmada-io/karmada/pkg/karmadactl/options" @@ -310,6 +311,18 @@ func (j *CommandUnregisterOption) getKarmadaAgentConfig(agent *appsv1.Deployment // RunUnregisterCluster unregister the pull mode cluster from karmada. func (j *CommandUnregisterOption) RunUnregisterCluster() error { + target, err := j.ControlPlaneClient.ClusterV1alpha1().Clusters().Get(context.TODO(), j.ClusterName, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + return fmt.Errorf("no cluster object %s found in karmada control Plane", j.ClusterName) + } + if err != nil { + klog.Errorf("Failed to get cluster object. cluster name: %s, error: %v", j.ClusterName, err) + return err + } + if target.Spec.SyncMode == clusterv1alpha1.Push { + return fmt.Errorf("cluster %s is a %s mode member cluster, please use command `unjoin` if you want to continue unjoining the cluster", j.ClusterName, target.Spec.SyncMode) + } + if j.DryRun { return nil } @@ -318,7 +331,7 @@ func (j *CommandUnregisterOption) RunUnregisterCluster() error { // 1. delete the work object from the Karmada control plane // When deleting a cluster, the deletion triggers the removal of executionSpace, which can lead to the deletion of RBAC roles related to work. // Therefore, the deletion of work should be performed before deleting the cluster. - err := cmdutil.EnsureWorksDeleted(j.ControlPlaneClient, names.GenerateExecutionSpaceName(j.ClusterName), j.Wait) + err = cmdutil.EnsureWorksDeleted(j.ControlPlaneClient, names.GenerateExecutionSpaceName(j.ClusterName), j.Wait) if err != nil { klog.Errorf("Failed to delete works object. cluster name: %s, error: %v", j.ClusterName, err) return err diff --git a/pkg/karmadactl/unregister/unregister_test.go b/pkg/karmadactl/unregister/unregister_test.go index 5a9176bc2f7c..3fade38eb9e3 100644 --- a/pkg/karmadactl/unregister/unregister_test.go +++ b/pkg/karmadactl/unregister/unregister_test.go @@ -200,11 +200,23 @@ func TestCommandUnregisterOption_RunUnregisterCluster(t *testing.T) { wantErr: true, }, { - name: "cluster exist, but cluster resources not found", - clusterObject: []runtime.Object{&clusterv1alpha1.Cluster{ObjectMeta: metav1.ObjectMeta{Name: clusterName}}}, + name: "cluster exist, but cluster resources not found", + clusterObject: []runtime.Object{&clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: clusterName}, + Spec: clusterv1alpha1.ClusterSpec{SyncMode: clusterv1alpha1.Pull}}, + }, clusterResources: []runtime.Object{}, wantErr: false, }, + { + name: "push mode member cluster", + clusterObject: []runtime.Object{&clusterv1alpha1.Cluster{ + ObjectMeta: metav1.ObjectMeta{Name: clusterName}, + Spec: clusterv1alpha1.ClusterSpec{SyncMode: clusterv1alpha1.Push}}, + }, + clusterResources: []runtime.Object{}, + wantErr: true, + }, } for _, tt := range tests {