Skip to content

Commit

Permalink
Introduce --wait flag for karmada join or unjoin command
Browse files Browse the repository at this point in the history
Signed-off-by: wawa0210 <[email protected]>
  • Loading branch information
wawa0210 committed Oct 31, 2021
1 parent 5bdf27d commit 78603cc
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 12 deletions.
1 change: 1 addition & 0 deletions pkg/clusterdiscovery/clusterapi/clusterapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ func (d *ClusterDetector) unJoinClusterAPICluster(clusterName string) error {
DryRun: false,
},
ClusterName: clusterName,
Wait: options.DefaultKarmadactlCommandDuration,
}
err := karmadactl.UnJoinCluster(d.ControllerPlaneConfig, nil, opts)
if err != nil {
Expand Down
9 changes: 8 additions & 1 deletion pkg/karmadactl/options/global.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package options

import "github.com/spf13/pflag"
import (
"time"

"github.com/spf13/pflag"
)

// DefaultKarmadaClusterNamespace defines the default namespace where the member cluster objects are stored.
// The secret owns by cluster objects will be stored in the namespace too.
const DefaultKarmadaClusterNamespace = "karmada-cluster"

// DefaultKarmadactlCommandDuration defines the default timeout for karmadactl execute
const DefaultKarmadactlCommandDuration = 60 * time.Second

// GlobalCommandOptions holds the configuration shared by the all sub-commands of `karmadactl`.
type GlobalCommandOptions struct {
// KubeConfig holds the control plane KUBECONFIG file path.
Expand Down
49 changes: 38 additions & 11 deletions pkg/karmadactl/unjoin.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/spf13/pflag"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/apimachinery/pkg/util/wait"
kubeclient "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
Expand All @@ -26,7 +27,11 @@ var (
unjoinShort = `Remove the registration of a cluster from control plane`
unjoinLong = `Unjoin removes the registration of a cluster from control plane.`
unjoinExample = `
# Unjoin cluster from karamada control plane
%s unjoin CLUSTER_NAME --cluster-kubeconfig=<KUBECONFIG>
# Unjoin cluster from karamada control plane with timeout
%s unjoin CLUSTER_NAME --cluster-kubeconfig=<KUBECONFIG> --wait 2m
`
)

Expand All @@ -38,12 +43,15 @@ func NewCmdUnjoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, cmdStr string)
Use: "unjoin CLUSTER_NAME --cluster-kubeconfig=<KUBECONFIG>",
Short: unjoinShort,
Long: unjoinLong,
Example: fmt.Sprintf(unjoinExample, cmdStr),
Example: getUnjoinExample(cmdStr),
Run: func(cmd *cobra.Command, args []string) {
err := opts.Complete(args)
if err != nil {
klog.Fatalf("Error: %v", err)
}
if errs := opts.Validate(); len(errs) != 0 {
klog.Fatalf("Error: %v", utilerrors.NewAggregate(errs).Error())
}

err = RunUnjoin(cmdOut, karmadaConfig, opts)
if err != nil {
Expand All @@ -58,6 +66,10 @@ func NewCmdUnjoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, cmdStr string)
return cmd
}

func getUnjoinExample(cmdStr string) string {
return fmt.Sprintf(unjoinExample, cmdStr, cmdStr)
}

// CommandUnjoinOption holds all command options.
type CommandUnjoinOption struct {
options.GlobalCommandOptions
Expand All @@ -72,6 +84,9 @@ type CommandUnjoinOption struct {
ClusterKubeConfig string

forceDeletion bool

// Wait tells maximum command execution time
Wait time.Duration
}

// Complete ensures that options are valid and marshals them if necessary.
Expand All @@ -90,6 +105,16 @@ func (j *CommandUnjoinOption) Complete(args []string) error {
return nil
}

// Validate ensures that command unjoin options are valid.
func (j *CommandUnjoinOption) Validate() []error {
var errs []error

if j.Wait < 0 {
errs = append(errs, fmt.Errorf(" --wait %v must be a positive duration, e.g. 1m0s ", j.Wait))
}
return errs
}

// AddFlags adds flags to the specified FlagSet.
func (j *CommandUnjoinOption) AddFlags(flags *pflag.FlagSet) {
j.GlobalCommandOptions.AddFlags(flags)
Expand All @@ -100,6 +125,8 @@ func (j *CommandUnjoinOption) AddFlags(flags *pflag.FlagSet) {
"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.")

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.")
}

// RunUnjoin is the implementation of the 'unjoin' command.
Expand Down Expand Up @@ -133,7 +160,7 @@ func UnJoinCluster(controlPlaneRestConfig, clusterConfig *rest.Config, opts Comm
controlPlaneKarmadaClient := karmadaclientset.NewForConfigOrDie(controlPlaneRestConfig)

// delete the cluster object in host cluster that associates the unjoining cluster
err = deleteClusterObject(controlPlaneKarmadaClient, opts.ClusterName, opts.DryRun)
err = deleteClusterObject(controlPlaneKarmadaClient, opts)
if err != nil {
klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", opts.ClusterName, err)
return err
Expand Down Expand Up @@ -236,35 +263,35 @@ func deleteNamespaceFromUnjoinCluster(clusterKubeClient kubeclient.Interface, na
}

// deleteClusterObject delete the cluster object in host cluster that associates the unjoining cluster
func deleteClusterObject(controlPlaneKarmadaClient *karmadaclientset.Clientset, clusterName string, dryRun bool) error {
if dryRun {
func deleteClusterObject(controlPlaneKarmadaClient *karmadaclientset.Clientset, opts CommandUnjoinOption) error {
if opts.DryRun {
return nil
}

err := controlPlaneKarmadaClient.ClusterV1alpha1().Clusters().Delete(context.TODO(), clusterName, metav1.DeleteOptions{})
err := controlPlaneKarmadaClient.ClusterV1alpha1().Clusters().Delete(context.TODO(), opts.ClusterName, metav1.DeleteOptions{})
if apierrors.IsNotFound(err) {
return nil
}
if err != nil {
klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", clusterName, err)
klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", opts.ClusterName, err)
return err
}

// make sure the given cluster object has been deleted
err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) {
_, err = controlPlaneKarmadaClient.ClusterV1alpha1().Clusters().Get(context.TODO(), clusterName, metav1.GetOptions{})
err = wait.Poll(1*time.Second, opts.Wait, func() (done bool, err error) {
_, err = controlPlaneKarmadaClient.ClusterV1alpha1().Clusters().Get(context.TODO(), opts.ClusterName, metav1.GetOptions{})
if apierrors.IsNotFound(err) {
return true, nil
}
if err != nil {
klog.Errorf("Failed to get cluster %s. err: %v", clusterName, err)
klog.Errorf("Failed to get cluster %s. err: %v", opts.ClusterName, err)
return false, err
}
klog.Infof("Waiting for the cluster object %s to be deleted", clusterName)
klog.Infof("Waiting for the cluster object %s to be deleted", opts.ClusterName)
return false, nil
})
if err != nil {
klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", clusterName, err)
klog.Errorf("Failed to delete cluster object. cluster name: %s, error: %v", opts.ClusterName, err)
return err
}

Expand Down
1 change: 1 addition & 0 deletions test/e2e/namespace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ var _ = ginkgo.Describe("[namespace auto-provision] namespace auto-provision tes
ClusterName: clusterName,
ClusterContext: clusterContext,
ClusterKubeConfig: kubeConfigPath,
Wait: options.DefaultKarmadactlCommandDuration,
}
err := karmadactl.RunUnjoin(os.Stdout, karmadaConfig, opts)
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
Expand Down

0 comments on commit 78603cc

Please sign in to comment.