rename membercluster to cluster in join unjoin

Signed-off-by: Kevin Wang <kevinwzf0126@gmail.com>
This commit is contained in:
Kevin Wang 2021-01-23 00:18:25 +08:00 committed by Hongcai Ren
parent e33559250c
commit 2840ea248f
4 changed files with 90 additions and 90 deletions

View File

@ -172,8 +172,8 @@ util::check_clusters_ready ${MEMBER_CLUSTER_2_KUBECONFIG} "member2"
# join member clusters # join member clusters
export KUBECONFIG=${KARMADA_APISERVER_CONFIG} export KUBECONFIG=${KARMADA_APISERVER_CONFIG}
${KARMADACTL_BIN} join member1 --member-cluster-kubeconfig="${MEMBER_CLUSTER_1_KUBECONFIG}" ${KARMADACTL_BIN} join member1 --cluster-kubeconfig="${MEMBER_CLUSTER_1_KUBECONFIG}"
${KARMADACTL_BIN} join member2 --member-cluster-kubeconfig="${MEMBER_CLUSTER_2_KUBECONFIG}" ${KARMADACTL_BIN} join member2 --cluster-kubeconfig="${MEMBER_CLUSTER_2_KUBECONFIG}"
function print_success() { function print_success() {
echo echo

View File

@ -26,10 +26,10 @@ import (
) )
var ( var (
joinLong = `Join registers a member cluster to control plane.` joinLong = `Join registers a cluster to control plane.`
joinExample = ` joinExample = `
karmadactl join CLUSTER_NAME --member-cluster-kubeconfig=<KUBECONFIG> karmadactl join CLUSTER_NAME --cluster-kubeconfig=<KUBECONFIG>
` `
) )
@ -65,8 +65,8 @@ func NewCmdJoin(cmdOut io.Writer, karmadaConfig KarmadaConfig) *cobra.Command {
opts := CommandJoinOption{} opts := CommandJoinOption{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "join CLUSTER_NAME --member-cluster-kubeconfig=<KUBECONFIG>", Use: "join CLUSTER_NAME --cluster-kubeconfig=<KUBECONFIG>",
Short: "Register a member cluster to control plane", Short: "Register a cluster to control plane",
Long: joinLong, Long: joinLong,
Example: joinExample, Example: joinExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
@ -94,25 +94,25 @@ func NewCmdJoin(cmdOut io.Writer, karmadaConfig KarmadaConfig) *cobra.Command {
type CommandJoinOption struct { type CommandJoinOption struct {
options.GlobalCommandOptions options.GlobalCommandOptions
// ClusterName is the member cluster's name that we are going to join with. // ClusterName is the cluster's name that we are going to join with.
ClusterName string ClusterName string
// ClusterContext is the member cluster's context that we are going to join with. // ClusterContext is the cluster's context that we are going to join with.
ClusterContext string ClusterContext string
// ClusterKubeConfig is the member cluster's kubeconfig path. // ClusterKubeConfig is the cluster's kubeconfig path.
ClusterKubeConfig string ClusterKubeConfig string
} }
// Complete ensures that options are valid and marshals them if necessary. // Complete ensures that options are valid and marshals them if necessary.
func (j *CommandJoinOption) Complete(args []string) error { func (j *CommandJoinOption) Complete(args []string) error {
// Get member cluster name from the command args. // Get cluster name from the command args.
if len(args) == 0 { if len(args) == 0 {
return errors.New("member cluster name is required") return errors.New("cluster name is required")
} }
j.ClusterName = args[0] j.ClusterName = args[0]
// If '--member-cluster-context' not specified, take the cluster name as the context. // If '--cluster-context' not specified, take the cluster name as the context.
if len(j.ClusterContext) == 0 { if len(j.ClusterContext) == 0 {
j.ClusterContext = j.ClusterName j.ClusterContext = j.ClusterName
} }
@ -124,49 +124,49 @@ func (j *CommandJoinOption) Complete(args []string) error {
func (j *CommandJoinOption) AddFlags(flags *pflag.FlagSet) { func (j *CommandJoinOption) AddFlags(flags *pflag.FlagSet) {
j.GlobalCommandOptions.AddFlags(flags) j.GlobalCommandOptions.AddFlags(flags)
flags.StringVar(&j.ClusterContext, "member-cluster-context", "", flags.StringVar(&j.ClusterContext, "cluster-context", "",
"Context name of member cluster in kubeconfig. Only works when there are multiple contexts in the kubeconfig.") "Context name of cluster in kubeconfig. Only works when there are multiple contexts in the kubeconfig.")
flags.StringVar(&j.ClusterKubeConfig, "member-cluster-kubeconfig", "", flags.StringVar(&j.ClusterKubeConfig, "cluster-kubeconfig", "",
"Path of the member cluster's kubeconfig.") "Path of the cluster's kubeconfig.")
} }
// RunJoin is the implementation of the 'join' command. // RunJoin is the implementation of the 'join' command.
// TODO(RainbowMango): consider to remove the 'KarmadaConfig'. // TODO(RainbowMango): consider to remove the 'KarmadaConfig'.
func RunJoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, opts CommandJoinOption) error { func RunJoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, opts CommandJoinOption) error {
klog.V(1).Infof("joining member cluster. member cluster name: %s", opts.ClusterName) klog.V(1).Infof("joining cluster. cluster name: %s", opts.ClusterName)
klog.V(1).Infof("joining member cluster. cluster namespace: %s", opts.ClusterNamespace) klog.V(1).Infof("joining cluster. cluster namespace: %s", opts.ClusterNamespace)
// Get control plane kube-apiserver client // Get control plane kube-apiserver client
controlPlaneRestConfig, err := karmadaConfig.GetRestConfig(opts.ClusterContext, opts.KubeConfig) controlPlaneRestConfig, err := karmadaConfig.GetRestConfig(opts.KarmadaContext, opts.KubeConfig)
if err != nil { if err != nil {
klog.Errorf("failed to get control plane rest config. context: %s, kube-config: %s, error: %v", klog.Errorf("failed to get control plane rest config. context: %s, kube-config: %s, error: %v",
opts.ClusterContext, opts.KubeConfig, err) opts.KarmadaContext, opts.KubeConfig, err)
return err return err
} }
controlPlaneKarmadaClient := karmadaclientset.NewForConfigOrDie(controlPlaneRestConfig) controlPlaneKarmadaClient := karmadaclientset.NewForConfigOrDie(controlPlaneRestConfig)
controlPlaneKubeClient := kubeclient.NewForConfigOrDie(controlPlaneRestConfig) controlPlaneKubeClient := kubeclient.NewForConfigOrDie(controlPlaneRestConfig)
// Get member cluster config // Get cluster config
clusterConfig, err := karmadaConfig.GetRestConfig(opts.ClusterContext, opts.ClusterKubeConfig) clusterConfig, err := karmadaConfig.GetRestConfig(opts.ClusterContext, opts.ClusterKubeConfig)
if err != nil { if err != nil {
klog.V(1).Infof("failed to get joining member cluster config. error: %v", err) klog.V(1).Infof("failed to get joining cluster config. error: %v", err)
return err return err
} }
clusterKubeClient := kubeclient.NewForConfigOrDie(clusterConfig) clusterKubeClient := kubeclient.NewForConfigOrDie(clusterConfig)
klog.V(1).Infof("joining member cluster config. endpoint: %s", clusterConfig.Host) klog.V(1).Infof("joining cluster config. endpoint: %s", clusterConfig.Host)
// ensure namespace where the member cluster object be stored exists in control plane. // ensure namespace where the cluster object be stored exists in control plane.
if _, err := ensureNamespaceExist(controlPlaneKubeClient, opts.ClusterNamespace, opts.DryRun); err != nil { if _, err := ensureNamespaceExist(controlPlaneKubeClient, opts.ClusterNamespace, opts.DryRun); err != nil {
return err return err
} }
// ensure namespace where the karmada control plane credential be stored exists in member cluster. // ensure namespace where the karmada control plane credential be stored exists in cluster.
if _, err := ensureNamespaceExist(clusterKubeClient, opts.ClusterNamespace, opts.DryRun); err != nil { if _, err := ensureNamespaceExist(clusterKubeClient, opts.ClusterNamespace, opts.DryRun); err != nil {
return err return err
} }
// create a ServiceAccount in member cluster. // create a ServiceAccount in cluster.
serviceAccountObj := &corev1.ServiceAccount{} serviceAccountObj := &corev1.ServiceAccount{}
serviceAccountObj.Namespace = opts.ClusterNamespace serviceAccountObj.Namespace = opts.ClusterNamespace
serviceAccountObj.Name = names.GenerateServiceAccountName(opts.ClusterName) serviceAccountObj.Name = names.GenerateServiceAccountName(opts.ClusterName)
@ -174,7 +174,7 @@ func RunJoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, opts CommandJoinOpti
return err return err
} }
// create a ClusterRole in member cluster. // create a ClusterRole in cluster.
clusterRole := &rbacv1.ClusterRole{} clusterRole := &rbacv1.ClusterRole{}
clusterRole.Name = names.GenerateRoleName(serviceAccountObj.Name) clusterRole.Name = names.GenerateRoleName(serviceAccountObj.Name)
clusterRole.Rules = clusterPolicyRules clusterRole.Rules = clusterPolicyRules
@ -182,7 +182,7 @@ func RunJoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, opts CommandJoinOpti
return err return err
} }
// create a ClusterRoleBinding in member cluster. // create a ClusterRoleBinding in cluster.
clusterRoleBinding := &rbacv1.ClusterRoleBinding{} clusterRoleBinding := &rbacv1.ClusterRoleBinding{}
clusterRoleBinding.Name = clusterRole.Name clusterRoleBinding.Name = clusterRole.Name
clusterRoleBinding.Subjects = buildRoleBindingSubjects(serviceAccountObj.Name, serviceAccountObj.Namespace) clusterRoleBinding.Subjects = buildRoleBindingSubjects(serviceAccountObj.Name, serviceAccountObj.Namespace)
@ -192,11 +192,11 @@ func RunJoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, opts CommandJoinOpti
} }
var clusterSecret *corev1.Secret var clusterSecret *corev1.Secret
// It will take a short time to create service account secret for member cluster. // It will take a short time to create service account secret for cluster.
err = wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) { err = wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) {
serviceAccountObj, err = clusterKubeClient.CoreV1().ServiceAccounts(serviceAccountObj.Namespace).Get(context.TODO(), serviceAccountObj.Name, metav1.GetOptions{}) serviceAccountObj, err = clusterKubeClient.CoreV1().ServiceAccounts(serviceAccountObj.Namespace).Get(context.TODO(), serviceAccountObj.Name, metav1.GetOptions{})
if err != nil { if err != nil {
klog.Errorf("Failed to retrieve service account(%s/%s) from member cluster. err: %v", serviceAccountObj.Namespace, serviceAccountObj.Name, err) klog.Errorf("Failed to retrieve service account(%s/%s) from cluster. err: %v", serviceAccountObj.Namespace, serviceAccountObj.Name, err)
return false, err return false, err
} }
clusterSecret, err = util.GetTargetSecret(clusterKubeClient, serviceAccountObj.Secrets, corev1.SecretTypeServiceAccountToken, opts.ClusterNamespace) clusterSecret, err = util.GetTargetSecret(clusterKubeClient, serviceAccountObj.Secrets, corev1.SecretTypeServiceAccountToken, opts.ClusterNamespace)
@ -207,7 +207,7 @@ func RunJoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, opts CommandJoinOpti
return true, nil return true, nil
}) })
if err != nil { if err != nil {
klog.Errorf("Failed to get service account secret from member cluster. error: %v", err) klog.Errorf("Failed to get service account secret from cluster. error: %v", err)
return err return err
} }
@ -243,7 +243,7 @@ func RunJoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, opts CommandJoinOpti
} }
cluster, err := createClusterObject(controlPlaneKarmadaClient, clusterObj, false) cluster, err := createClusterObject(controlPlaneKarmadaClient, clusterObj, false)
if err != nil { if err != nil {
klog.Errorf("failed to create member cluster object. cluster name: %s, error: %v", opts.ClusterName, err) klog.Errorf("failed to create cluster object. cluster name: %s, error: %v", opts.ClusterName, err)
return err return err
} }
@ -375,29 +375,29 @@ func ensureClusterRoleBindingExist(client kubeclient.Interface, clusterRoleBindi
func createClusterObject(controlPlaneClient *karmadaclientset.Clientset, clusterObj *clusterapi.Cluster, errorOnExisting bool) (*clusterapi.Cluster, error) { func createClusterObject(controlPlaneClient *karmadaclientset.Clientset, clusterObj *clusterapi.Cluster, errorOnExisting bool) (*clusterapi.Cluster, error) {
cluster, exist, err := GetCluster(controlPlaneClient, clusterObj.Namespace, clusterObj.Name) cluster, exist, err := GetCluster(controlPlaneClient, clusterObj.Namespace, clusterObj.Name)
if err != nil { if err != nil {
klog.Errorf("failed to create member cluster object. member cluster: %s/%s, error: %v", clusterObj.Namespace, clusterObj.Name, err) klog.Errorf("failed to create cluster object. cluster: %s/%s, error: %v", clusterObj.Namespace, clusterObj.Name, err)
return nil, err return nil, err
} }
if exist { if exist {
if errorOnExisting { if errorOnExisting {
klog.Errorf("failed to create member cluster object. member cluster: %s/%s, error: %v", clusterObj.Namespace, clusterObj.Name, err) klog.Errorf("failed to create cluster object. cluster: %s/%s, error: %v", clusterObj.Namespace, clusterObj.Name, err)
return cluster, err return cluster, err
} }
klog.V(1).Infof("create member cluster succeed as already exist. member cluster: %s/%s", clusterObj.Namespace, clusterObj.Name) klog.V(1).Infof("create cluster succeed as already exist. cluster: %s/%s", clusterObj.Namespace, clusterObj.Name)
return cluster, nil return cluster, nil
} }
if cluster, err = CreateCluster(controlPlaneClient, clusterObj); err != nil { if cluster, err = CreateCluster(controlPlaneClient, clusterObj); err != nil {
klog.Warningf("failed to create member cluster. member cluster: %s/%s, error: %v", clusterObj.Namespace, clusterObj.Name, err) klog.Warningf("failed to create cluster. cluster: %s/%s, error: %v", clusterObj.Namespace, clusterObj.Name, err)
return nil, err return nil, err
} }
return cluster, nil return cluster, nil
} }
// GetCluster tells if a member cluster (namespace/name) already joined to control plane. // GetCluster tells if a cluster (namespace/name) already joined to control plane.
func GetCluster(client karmadaclientset.Interface, namespace string, name string) (*clusterapi.Cluster, bool, error) { func GetCluster(client karmadaclientset.Interface, namespace string, name string) (*clusterapi.Cluster, bool, error) {
cluster, err := client.ClusterV1alpha1().Clusters().Get(context.TODO(), name, metav1.GetOptions{}) cluster, err := client.ClusterV1alpha1().Clusters().Get(context.TODO(), name, metav1.GetOptions{})
if err != nil { if err != nil {
@ -405,18 +405,18 @@ func GetCluster(client karmadaclientset.Interface, namespace string, name string
return nil, false, nil return nil, false, nil
} }
klog.Warningf("failed to retrieve member cluster. member cluster: %s/%s, error: %v", namespace, name, err) klog.Warningf("failed to retrieve cluster. cluster: %s/%s, error: %v", namespace, name, err)
return nil, false, err return nil, false, err
} }
return cluster, true, nil return cluster, true, nil
} }
// CreateCluster creates a new member cluster object in control plane. // CreateCluster creates a new cluster object in control plane.
func CreateCluster(controlPlaneClient karmadaclientset.Interface, cluster *clusterapi.Cluster) (*clusterapi.Cluster, error) { func CreateCluster(controlPlaneClient karmadaclientset.Interface, cluster *clusterapi.Cluster) (*clusterapi.Cluster, error) {
cluster, err := controlPlaneClient.ClusterV1alpha1().Clusters().Create(context.TODO(), cluster, metav1.CreateOptions{}) cluster, err := controlPlaneClient.ClusterV1alpha1().Clusters().Create(context.TODO(), cluster, metav1.CreateOptions{})
if err != nil { if err != nil {
klog.Warningf("failed to create member cluster. member cluster: %s/%s, error: %v", cluster.Namespace, cluster.Name, err) klog.Warningf("failed to create cluster. cluster: %s/%s, error: %v", cluster.Namespace, cluster.Name, err)
return cluster, err return cluster, err
} }

View File

@ -13,7 +13,7 @@ type GlobalCommandOptions struct {
// ClusterContext is the name of the cluster context in control plane KUBECONFIG file. // ClusterContext is the name of the cluster context in control plane KUBECONFIG file.
// Default value is the current-context. // Default value is the current-context.
ClusterContext string KarmadaContext string
// ClusterNamespace holds the namespace name where the member cluster objects are stored. // ClusterNamespace holds the namespace name where the member cluster objects are stored.
ClusterNamespace string ClusterNamespace string
@ -25,7 +25,7 @@ type GlobalCommandOptions struct {
// AddFlags adds flags to the specified FlagSet. // AddFlags adds flags to the specified FlagSet.
func (o *GlobalCommandOptions) AddFlags(flags *pflag.FlagSet) { func (o *GlobalCommandOptions) AddFlags(flags *pflag.FlagSet) {
flags.StringVar(&o.KubeConfig, "kubeconfig", "", "Path to the control plane KUBECONFIG file.") flags.StringVar(&o.KubeConfig, "kubeconfig", "", "Path to the control plane KUBECONFIG file.")
flags.StringVar(&o.ClusterContext, "cluster-context", "", "Name of the cluster context in control plane KUBECONFIG file.") flags.StringVar(&o.KarmadaContext, "karmada-context", "", "Name of the cluster context in control plane KUBECONFIG file.")
flags.StringVar(&o.ClusterNamespace, "cluster-namespace", DefaultKarmadaClusterNamespace, "Namespace in the control plane where member cluster are stored.") flags.StringVar(&o.ClusterNamespace, "cluster-namespace", DefaultKarmadaClusterNamespace, "Namespace in the control plane where member cluster are stored.")
flags.BoolVar(&o.DryRun, "dry-run", false, "Run the command in dry-run mode, without making any server requests.") flags.BoolVar(&o.DryRun, "dry-run", false, "Run the command in dry-run mode, without making any server requests.")
} }

View File

@ -21,20 +21,20 @@ import (
) )
var ( var (
unjoinLong = `Unjoin removes the registration of a member cluster from control plane.` unjoinLong = `Unjoin removes the registration of a cluster from control plane.`
unjoinExample = ` unjoinExample = `
karmadactl unjoin CLUSTER_NAME --member-cluster-kubeconfig=<KUBECONFIG> karmadactl unjoin CLUSTER_NAME --cluster-kubeconfig=<KUBECONFIG>
` `
) )
// NewCmdUnjoin defines the `unjoin` command that removes registration of a member cluster from control plane. // NewCmdUnjoin defines the `unjoin` command that removes registration of a cluster from control plane.
func NewCmdUnjoin(cmdOut io.Writer, karmadaConfig KarmadaConfig) *cobra.Command { func NewCmdUnjoin(cmdOut io.Writer, karmadaConfig KarmadaConfig) *cobra.Command {
opts := CommandUnjoinOption{} opts := CommandUnjoinOption{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "unjoin CLUSTER_NAME --member-cluster-kubeconfig=<KUBECONFIG>", Use: "unjoin CLUSTER_NAME --cluster-kubeconfig=<KUBECONFIG>",
Short: "Remove the registration of a member cluster from control plane", Short: "Remove the registration of a cluster from control plane",
Long: unjoinLong, Long: unjoinLong,
Example: unjoinExample, Example: unjoinExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
@ -62,13 +62,13 @@ func NewCmdUnjoin(cmdOut io.Writer, karmadaConfig KarmadaConfig) *cobra.Command
type CommandUnjoinOption struct { type CommandUnjoinOption struct {
options.GlobalCommandOptions options.GlobalCommandOptions
// ClusterName is the member cluster's name that we are going to join with. // ClusterName is the cluster's name that we are going to join with.
ClusterName string ClusterName string
// ClusterContext is the member cluster's context that we are going to join with. // ClusterContext is the cluster's context that we are going to join with.
ClusterContext string ClusterContext string
// ClusterKubeConfig is the member cluster's kubeconfig path. // ClusterKubeConfig is the cluster's kubeconfig path.
ClusterKubeConfig string ClusterKubeConfig string
forceDeletion bool forceDeletion bool
@ -76,13 +76,13 @@ type CommandUnjoinOption struct {
// Complete ensures that options are valid and marshals them if necessary. // Complete ensures that options are valid and marshals them if necessary.
func (j *CommandUnjoinOption) Complete(args []string) error { func (j *CommandUnjoinOption) Complete(args []string) error {
// Get member cluster name from the command args. // Get cluster name from the command args.
if len(args) == 0 { if len(args) == 0 {
return errors.New("member cluster name is required") return errors.New("cluster name is required")
} }
j.ClusterName = args[0] j.ClusterName = args[0]
// If '--member-cluster-context' not specified, take the cluster name as the context. // If '--cluster-context' not specified, take the cluster name as the context.
if len(j.ClusterContext) == 0 { if len(j.ClusterContext) == 0 {
j.ClusterContext = j.ClusterName j.ClusterContext = j.ClusterName
} }
@ -94,33 +94,33 @@ func (j *CommandUnjoinOption) Complete(args []string) error {
func (j *CommandUnjoinOption) AddFlags(flags *pflag.FlagSet) { func (j *CommandUnjoinOption) AddFlags(flags *pflag.FlagSet) {
j.GlobalCommandOptions.AddFlags(flags) j.GlobalCommandOptions.AddFlags(flags)
flags.StringVar(&j.ClusterContext, "member-cluster-context", "", flags.StringVar(&j.ClusterContext, "cluster-context", "",
"Context name of member cluster in kubeconfig. Only works when there are multiple contexts in the kubeconfig.") "Context name of cluster in kubeconfig. Only works when there are multiple contexts in the kubeconfig.")
flags.StringVar(&j.ClusterKubeConfig, "member-cluster-kubeconfig", "", flags.StringVar(&j.ClusterKubeConfig, "cluster-kubeconfig", "",
"Path of the member cluster's kubeconfig.") "Path of the cluster's kubeconfig.")
flags.BoolVar(&j.forceDeletion, "force", false, flags.BoolVar(&j.forceDeletion, "force", false,
"Delete cluster and secret resources even if resources in the member cluster targeted for unjoin are not removed successfully.") "Delete cluster and secret resources even if resources in the cluster targeted for unjoin are not removed successfully.")
} }
// RunUnjoin is the implementation of the 'unjoin' command. // RunUnjoin is the implementation of the 'unjoin' command.
// TODO(RainbowMango): consider to remove the 'KarmadaConfig'. // TODO(RainbowMango): consider to remove the 'KarmadaConfig'.
func RunUnjoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, opts CommandUnjoinOption) error { func RunUnjoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, opts CommandUnjoinOption) error {
klog.V(1).Infof("unjoining member cluster. member cluster name: %s", opts.ClusterName) klog.V(1).Infof("unjoining cluster. cluster name: %s", opts.ClusterName)
klog.V(1).Infof("unjoining member cluster. cluster namespace: %s", opts.ClusterNamespace) klog.V(1).Infof("unjoining cluster. cluster namespace: %s", opts.ClusterNamespace)
// Get control plane kube-apiserver client // Get control plane kube-apiserver client
controlPlaneRestConfig, err := karmadaConfig.GetRestConfig(opts.ClusterContext, opts.KubeConfig) controlPlaneRestConfig, err := karmadaConfig.GetRestConfig(opts.KarmadaContext, opts.KubeConfig)
if err != nil { if err != nil {
klog.Errorf("failed to get control plane rest config. context: %s, kube-config: %s, error: %v", klog.Errorf("failed to get control plane rest config. context: %s, kube-config: %s, error: %v",
opts.ClusterContext, opts.KubeConfig, err) opts.KarmadaContext, opts.KubeConfig, err)
return err return err
} }
controlPlaneKarmadaClient := karmadaclientset.NewForConfigOrDie(controlPlaneRestConfig) controlPlaneKarmadaClient := karmadaclientset.NewForConfigOrDie(controlPlaneRestConfig)
controlPlaneKubeClient := kubeclient.NewForConfigOrDie(controlPlaneRestConfig) controlPlaneKubeClient := kubeclient.NewForConfigOrDie(controlPlaneRestConfig)
// todo: taint member cluster object instead of deleting execution space. // todo: taint cluster object instead of deleting execution space.
// Once the member cluster is tainted, eviction controller will delete all propagationwork in the execution space of the member cluster. // Once the cluster is tainted, eviction controller will delete all propagationwork in the execution space of the cluster.
executionSpaceName, err := names.GenerateExecutionSpaceName(opts.ClusterName) executionSpaceName, err := names.GenerateExecutionSpaceName(opts.ClusterName)
if err != nil { if err != nil {
return err return err
@ -132,52 +132,52 @@ func RunUnjoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, opts CommandUnjoin
return err return err
} }
// Attempt to delete the cluster role, cluster rolebindings and service account from the unjoining member cluster // Attempt to delete the cluster role, cluster rolebindings and service account from the unjoining cluster
// if user provides the kubeconfig of member cluster // if user provides the kubeconfig of cluster
if opts.ClusterKubeConfig != "" { if opts.ClusterKubeConfig != "" {
// Get member cluster config // Get cluster config
clusterConfig, err := karmadaConfig.GetRestConfig(opts.ClusterContext, opts.ClusterKubeConfig) clusterConfig, err := karmadaConfig.GetRestConfig(opts.ClusterContext, opts.ClusterKubeConfig)
if err != nil { if err != nil {
klog.V(1).Infof("failed to get unjoining member cluster config. error: %v", err) klog.V(1).Infof("failed to get unjoining cluster config. error: %v", err)
return err return err
} }
clusterKubeClient := kubeclient.NewForConfigOrDie(clusterConfig) clusterKubeClient := kubeclient.NewForConfigOrDie(clusterConfig)
klog.V(1).Infof("unjoining member cluster config. endpoint: %s", clusterConfig.Host) klog.V(1).Infof("unjoining cluster config. endpoint: %s", clusterConfig.Host)
// delete RBAC resource from unjoining member cluster // delete RBAC resource from unjoining cluster
err = deleteRBACResources(clusterKubeClient, opts.ClusterName, opts.forceDeletion, opts.DryRun) err = deleteRBACResources(clusterKubeClient, opts.ClusterName, opts.forceDeletion, opts.DryRun)
if err != nil { if err != nil {
klog.Errorf("Failed to delete RBAC resource in unjoining member cluster %q: %v", opts.ClusterName, err) klog.Errorf("Failed to delete RBAC resource in unjoining cluster %q: %v", opts.ClusterName, err)
return err return err
} }
// delete service account from unjoining member cluster // delete service account from unjoining cluster
err = deleteServiceAccount(clusterKubeClient, opts.ClusterNamespace, opts.ClusterName, opts.forceDeletion, opts.DryRun) err = deleteServiceAccount(clusterKubeClient, opts.ClusterNamespace, opts.ClusterName, opts.forceDeletion, opts.DryRun)
if err != nil { if err != nil {
klog.Errorf("Failed to delete service account in unjoining member cluster %q: %v", opts.ClusterName, err) klog.Errorf("Failed to delete service account in unjoining cluster %q: %v", opts.ClusterName, err)
return err return err
} }
// delete namespace from unjoining member cluster // delete namespace from unjoining cluster
err = deleteNamespaceFromUnjoinCluster(clusterKubeClient, opts.ClusterNamespace, opts.ClusterName, opts.forceDeletion, opts.DryRun) err = deleteNamespaceFromUnjoinCluster(clusterKubeClient, opts.ClusterNamespace, opts.ClusterName, opts.forceDeletion, opts.DryRun)
if err != nil { if err != nil {
klog.Errorf("Failed to delete namespace in unjoining member cluster %q: %v", opts.ClusterName, err) klog.Errorf("Failed to delete namespace in unjoining cluster %q: %v", opts.ClusterName, err)
return err return err
} }
} }
// delete the member cluster object in host cluster that associates the unjoining member cluster // delete the cluster object in host cluster that associates the unjoining cluster
err = deleteClusterObject(controlPlaneKarmadaClient, opts.ClusterName, opts.DryRun) err = deleteClusterObject(controlPlaneKarmadaClient, opts.ClusterName, opts.DryRun)
if err != nil { if err != nil {
klog.Errorf("Failed to delete member cluster object. cluster name: %s, error: %v", opts.ClusterName, err) klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", opts.ClusterName, err)
return err return err
} }
return nil return nil
} }
// deleteRBACResources deletes the cluster role, cluster rolebindings from the unjoining member cluster. // deleteRBACResources deletes the cluster role, cluster rolebindings from the unjoining cluster.
func deleteRBACResources(clusterKubeClient kubeclient.Interface, unjoiningClusterName string, forceDeletion, dryRun bool) error { func deleteRBACResources(clusterKubeClient kubeclient.Interface, unjoiningClusterName string, forceDeletion, dryRun bool) error {
if dryRun { if dryRun {
return nil return nil
@ -192,7 +192,7 @@ func deleteRBACResources(clusterKubeClient kubeclient.Interface, unjoiningCluste
if !forceDeletion { if !forceDeletion {
return err return err
} }
klog.Errorf("Force deletion. Could not delete cluster role binding %q for service account %q in unjoining member cluster %q: %v.", clusterRoleBindingName, serviceAccountName, unjoiningClusterName, err) klog.Errorf("Force deletion. Could not delete cluster role binding %q for service account %q in unjoining cluster %q: %v.", clusterRoleBindingName, serviceAccountName, unjoiningClusterName, err)
} }
err = util.DeleteClusterRole(clusterKubeClient, clusterRoleName) err = util.DeleteClusterRole(clusterKubeClient, clusterRoleName)
@ -200,13 +200,13 @@ func deleteRBACResources(clusterKubeClient kubeclient.Interface, unjoiningCluste
if !forceDeletion { if !forceDeletion {
return err return err
} }
klog.Errorf("Force deletion. Could not delete cluster role %q for service account %q in unjoining member cluster %q: %v.", clusterRoleName, serviceAccountName, unjoiningClusterName, err) klog.Errorf("Force deletion. Could not delete cluster role %q for service account %q in unjoining cluster %q: %v.", clusterRoleName, serviceAccountName, unjoiningClusterName, err)
} }
return nil return nil
} }
// deleteServiceAccount deletes the service account from the unjoining member cluster. // deleteServiceAccount deletes the service account from the unjoining cluster.
func deleteServiceAccount(clusterKubeClient kubeclient.Interface, namespace, unjoiningClusterName string, forceDeletion, dryRun bool) error { func deleteServiceAccount(clusterKubeClient kubeclient.Interface, namespace, unjoiningClusterName string, forceDeletion, dryRun bool) error {
if dryRun { if dryRun {
return nil return nil
@ -218,13 +218,13 @@ func deleteServiceAccount(clusterKubeClient kubeclient.Interface, namespace, unj
if !forceDeletion { if !forceDeletion {
return err return err
} }
klog.Errorf("Force deletion. Could not delete service account %q in unjoining member cluster %q: %v.", serviceAccountName, unjoiningClusterName, err) klog.Errorf("Force deletion. Could not delete service account %q in unjoining cluster %q: %v.", serviceAccountName, unjoiningClusterName, err)
} }
return nil return nil
} }
// deleteNSFromUnjoinCluster deletes the namespace from the unjoining member cluster. // deleteNSFromUnjoinCluster deletes the namespace from the unjoining cluster.
func deleteNamespaceFromUnjoinCluster(clusterKubeClient kubeclient.Interface, namespace, unjoiningClusterName string, forceDeletion, dryRun bool) error { func deleteNamespaceFromUnjoinCluster(clusterKubeClient kubeclient.Interface, namespace, unjoiningClusterName string, forceDeletion, dryRun bool) error {
if dryRun { if dryRun {
return nil return nil
@ -235,7 +235,7 @@ func deleteNamespaceFromUnjoinCluster(clusterKubeClient kubeclient.Interface, na
if !forceDeletion { if !forceDeletion {
return err return err
} }
klog.Errorf("Force deletion. Could not delete namespace %q in unjoining member cluster %q: %v.", namespace, unjoiningClusterName, err) klog.Errorf("Force deletion. Could not delete namespace %q in unjoining cluster %q: %v.", namespace, unjoiningClusterName, err)
} }
return nil return nil
@ -272,7 +272,7 @@ func deleteExecutionSpace(hostClient kubeclient.Interface, namespace string, dry
return nil return nil
} }
// deleteClusterObject delete the member cluster object in host cluster that associates the unjoining member cluster // deleteClusterObject delete the cluster object in host cluster that associates the unjoining cluster
func deleteClusterObject(controlPlaneKarmadaClient *karmadaclientset.Clientset, clusterName string, dryRun bool) error { func deleteClusterObject(controlPlaneKarmadaClient *karmadaclientset.Clientset, clusterName string, dryRun bool) error {
if dryRun { if dryRun {
return nil return nil
@ -283,25 +283,25 @@ func deleteClusterObject(controlPlaneKarmadaClient *karmadaclientset.Clientset,
return nil return nil
} }
if err != nil { if err != nil {
klog.Errorf("Failed to delete member cluster object. cluster name: %s, error: %v", clusterName, err) klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", clusterName, err)
return err return err
} }
// make sure the given member cluster object has been deleted // make sure the given cluster object has been deleted
err = wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) { err = wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) {
_, err = controlPlaneKarmadaClient.ClusterV1alpha1().Clusters().Get(context.TODO(), clusterName, metav1.GetOptions{}) _, err = controlPlaneKarmadaClient.ClusterV1alpha1().Clusters().Get(context.TODO(), clusterName, metav1.GetOptions{})
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
return true, nil return true, nil
} }
if err != nil { if err != nil {
klog.Errorf("Failed to get member cluster %s. err: %v", clusterName, err) klog.Errorf("Failed to get cluster %s. err: %v", clusterName, err)
return false, err return false, err
} }
klog.Infof("Waiting for the member cluster object %s to be deleted", clusterName) klog.Infof("Waiting for the cluster object %s to be deleted", clusterName)
return false, nil return false, nil
}) })
if err != nil { if err != nil {
klog.Errorf("Failed to delete member cluster object. cluster name: %s, error: %v", clusterName, err) klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", clusterName, err)
return err return err
} }