Merge pull request #875 from wawa0210/karmadactl-wait-flag
Introduce --wait flag for karmada unjoin command
This commit is contained in:
commit
209be7f540
|
@ -198,6 +198,7 @@ func (d *ClusterDetector) unJoinClusterAPICluster(clusterName string) error {
|
||||||
DryRun: false,
|
DryRun: false,
|
||||||
},
|
},
|
||||||
ClusterName: clusterName,
|
ClusterName: clusterName,
|
||||||
|
Wait: options.DefaultKarmadactlCommandDuration,
|
||||||
}
|
}
|
||||||
err := karmadactl.UnJoinCluster(d.ControllerPlaneConfig, nil, opts)
|
err := karmadactl.UnJoinCluster(d.ControllerPlaneConfig, nil, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,11 +1,18 @@
|
||||||
package options
|
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.
|
// 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.
|
// The secret owns by cluster objects will be stored in the namespace too.
|
||||||
const DefaultKarmadaClusterNamespace = "karmada-cluster"
|
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`.
|
// GlobalCommandOptions holds the configuration shared by the all sub-commands of `karmadactl`.
|
||||||
type GlobalCommandOptions struct {
|
type GlobalCommandOptions struct {
|
||||||
// KubeConfig holds the control plane KUBECONFIG file path.
|
// KubeConfig holds the control plane KUBECONFIG file path.
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apimachinery/pkg/util/wait"
|
"k8s.io/apimachinery/pkg/util/wait"
|
||||||
kubeclient "k8s.io/client-go/kubernetes"
|
kubeclient "k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/client-go/rest"
|
"k8s.io/client-go/rest"
|
||||||
|
@ -26,7 +27,11 @@ var (
|
||||||
unjoinShort = `Remove the registration of a cluster from control plane`
|
unjoinShort = `Remove the registration of a cluster from control plane`
|
||||||
unjoinLong = `Unjoin removes the registration of a cluster from control plane.`
|
unjoinLong = `Unjoin removes the registration of a cluster from control plane.`
|
||||||
unjoinExample = `
|
unjoinExample = `
|
||||||
|
# Unjoin cluster from karamada control plane
|
||||||
%s unjoin CLUSTER_NAME --cluster-kubeconfig=<KUBECONFIG>
|
%s unjoin CLUSTER_NAME --cluster-kubeconfig=<KUBECONFIG>
|
||||||
|
|
||||||
|
# Unjoin cluster from karamada control plane with timeout
|
||||||
|
%s unjoin CLUSTER_NAME --cluster-kubeconfig=<KUBECONFIG> --wait 2m
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -38,12 +43,15 @@ func NewCmdUnjoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, cmdStr string)
|
||||||
Use: "unjoin CLUSTER_NAME --cluster-kubeconfig=<KUBECONFIG>",
|
Use: "unjoin CLUSTER_NAME --cluster-kubeconfig=<KUBECONFIG>",
|
||||||
Short: unjoinShort,
|
Short: unjoinShort,
|
||||||
Long: unjoinLong,
|
Long: unjoinLong,
|
||||||
Example: fmt.Sprintf(unjoinExample, cmdStr),
|
Example: getUnjoinExample(cmdStr),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
err := opts.Complete(args)
|
err := opts.Complete(args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
klog.Fatalf("Error: %v", err)
|
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)
|
err = RunUnjoin(cmdOut, karmadaConfig, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -58,6 +66,10 @@ func NewCmdUnjoin(cmdOut io.Writer, karmadaConfig KarmadaConfig, cmdStr string)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getUnjoinExample(cmdStr string) string {
|
||||||
|
return fmt.Sprintf(unjoinExample, cmdStr, cmdStr)
|
||||||
|
}
|
||||||
|
|
||||||
// CommandUnjoinOption holds all command options.
|
// CommandUnjoinOption holds all command options.
|
||||||
type CommandUnjoinOption struct {
|
type CommandUnjoinOption struct {
|
||||||
options.GlobalCommandOptions
|
options.GlobalCommandOptions
|
||||||
|
@ -72,6 +84,9 @@ type CommandUnjoinOption struct {
|
||||||
ClusterKubeConfig string
|
ClusterKubeConfig string
|
||||||
|
|
||||||
forceDeletion bool
|
forceDeletion bool
|
||||||
|
|
||||||
|
// Wait tells maximum command execution time
|
||||||
|
Wait time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complete ensures that options are valid and marshals them if necessary.
|
// Complete ensures that options are valid and marshals them if necessary.
|
||||||
|
@ -90,6 +105,16 @@ func (j *CommandUnjoinOption) Complete(args []string) error {
|
||||||
return nil
|
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.
|
// AddFlags adds flags to the specified FlagSet.
|
||||||
func (j *CommandUnjoinOption) AddFlags(flags *pflag.FlagSet) {
|
func (j *CommandUnjoinOption) AddFlags(flags *pflag.FlagSet) {
|
||||||
j.GlobalCommandOptions.AddFlags(flags)
|
j.GlobalCommandOptions.AddFlags(flags)
|
||||||
|
@ -100,6 +125,8 @@ func (j *CommandUnjoinOption) AddFlags(flags *pflag.FlagSet) {
|
||||||
"Path of the 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 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.")
|
||||||
|
|
||||||
|
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.
|
// RunUnjoin is the implementation of the 'unjoin' command.
|
||||||
|
@ -133,7 +160,7 @@ func UnJoinCluster(controlPlaneRestConfig, clusterConfig *rest.Config, opts Comm
|
||||||
controlPlaneKarmadaClient := karmadaclientset.NewForConfigOrDie(controlPlaneRestConfig)
|
controlPlaneKarmadaClient := karmadaclientset.NewForConfigOrDie(controlPlaneRestConfig)
|
||||||
|
|
||||||
// delete the cluster object in host cluster that associates the unjoining cluster
|
// 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 {
|
if err != nil {
|
||||||
klog.Errorf("Failed to delete 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
|
||||||
|
@ -236,35 +263,35 @@ func deleteNamespaceFromUnjoinCluster(clusterKubeClient kubeclient.Interface, na
|
||||||
}
|
}
|
||||||
|
|
||||||
// deleteClusterObject delete the cluster object in host cluster that associates the unjoining 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, opts CommandUnjoinOption) error {
|
||||||
if dryRun {
|
if opts.DryRun {
|
||||||
return nil
|
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) {
|
if apierrors.IsNotFound(err) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err != 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure the given cluster object has been deleted
|
// make sure the given cluster object has been deleted
|
||||||
err = wait.Poll(1*time.Second, 1*time.Minute, func() (done bool, err error) {
|
err = wait.Poll(1*time.Second, opts.Wait, func() (done bool, err error) {
|
||||||
_, err = controlPlaneKarmadaClient.ClusterV1alpha1().Clusters().Get(context.TODO(), clusterName, metav1.GetOptions{})
|
_, err = controlPlaneKarmadaClient.ClusterV1alpha1().Clusters().Get(context.TODO(), opts.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 cluster %s. err: %v", clusterName, err)
|
klog.Errorf("Failed to get cluster %s. err: %v", opts.ClusterName, err)
|
||||||
return false, 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
|
return false, nil
|
||||||
})
|
})
|
||||||
if err != 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -168,6 +168,7 @@ var _ = ginkgo.Describe("[namespace auto-provision] namespace auto-provision tes
|
||||||
ClusterName: clusterName,
|
ClusterName: clusterName,
|
||||||
ClusterContext: clusterContext,
|
ClusterContext: clusterContext,
|
||||||
ClusterKubeConfig: kubeConfigPath,
|
ClusterKubeConfig: kubeConfigPath,
|
||||||
|
Wait: options.DefaultKarmadactlCommandDuration,
|
||||||
}
|
}
|
||||||
err := karmadactl.RunUnjoin(os.Stdout, karmadaConfig, opts)
|
err := karmadactl.RunUnjoin(os.Stdout, karmadaConfig, opts)
|
||||||
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
|
||||||
|
|
Loading…
Reference in New Issue