From 3dc11037cc36bf3f8cc1aa90cd17e7eb8ffbac56 Mon Sep 17 00:00:00 2001 From: lonelyCZ Date: Mon, 7 Nov 2022 16:02:40 +0800 Subject: [PATCH] karmadactl join/unjoin use factory to access control plane Signed-off-by: lonelyCZ --- cmd/agent/app/agent.go | 10 +- .../app/controllermanager.go | 7 +- pkg/clusterdiscovery/clusterapi/clusterapi.go | 4 +- pkg/karmadactl/addons/init/disable_option.go | 4 +- pkg/karmadactl/addons/init/enable_option.go | 6 +- pkg/karmadactl/addons/init/global.go | 23 +- pkg/karmadactl/cmdinit/karmada/deploy.go | 13 +- pkg/karmadactl/cmdinit/kubernetes/deploy.go | 19 +- pkg/karmadactl/cmdinit/utils/kubeclient.go | 44 --- pkg/karmadactl/config.go | 54 --- pkg/karmadactl/deinit.go | 19 +- pkg/karmadactl/get.go | 9 - pkg/karmadactl/get_flags.go | 350 ------------------ pkg/karmadactl/join.go | 24 +- pkg/karmadactl/karmadactl.go | 6 +- pkg/karmadactl/options/global.go | 22 +- pkg/karmadactl/register.go | 18 +- pkg/karmadactl/unjoin.go | 24 +- pkg/karmadactl/util/apiclient/apiclient.go | 81 ++++ test/e2e/aggregatedapi_test.go | 21 +- test/e2e/federatedresourcequota_test.go | 20 +- test/e2e/karmadactl_test.go | 29 +- test/e2e/namespace_test.go | 20 +- test/e2e/rescheduling_test.go | 46 +-- 24 files changed, 194 insertions(+), 679 deletions(-) delete mode 100644 pkg/karmadactl/cmdinit/utils/kubeclient.go delete mode 100644 pkg/karmadactl/config.go delete mode 100644 pkg/karmadactl/get_flags.go create mode 100644 pkg/karmadactl/util/apiclient/apiclient.go diff --git a/cmd/agent/app/agent.go b/cmd/agent/app/agent.go index 11ea53575..9f3ea9717 100644 --- a/cmd/agent/app/agent.go +++ b/cmd/agent/app/agent.go @@ -12,7 +12,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/dynamic" kubeclientset "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" cliflag "k8s.io/component-base/cli/flag" "k8s.io/component-base/term" "k8s.io/klog/v2" @@ -30,7 +29,7 @@ import ( "github.com/karmada-io/karmada/pkg/controllers/mcs" "github.com/karmada-io/karmada/pkg/controllers/status" karmadaclientset "github.com/karmada-io/karmada/pkg/generated/clientset/versioned" - "github.com/karmada-io/karmada/pkg/karmadactl" + "github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient" "github.com/karmada-io/karmada/pkg/resourceinterpreter" "github.com/karmada-io/karmada/pkg/sharedcli" "github.com/karmada-io/karmada/pkg/sharedcli/klogflag" @@ -51,7 +50,6 @@ import ( // NewAgentCommand creates a *cobra.Command object with default parameters func NewAgentCommand(ctx context.Context) *cobra.Command { opts := options.NewOptions() - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) cmd := &cobra.Command{ Use: "karmada-agent", @@ -63,7 +61,7 @@ cluster and manifests to the Karmada control plane.`, if errs := opts.Validate(); len(errs) != 0 { return errs.ToAggregate() } - if err := run(ctx, karmadaConfig, opts); err != nil { + if err := run(ctx, opts); err != nil { return err } return nil @@ -111,12 +109,12 @@ func init() { controllers["certRotation"] = startCertRotationController } -func run(ctx context.Context, karmadaConfig karmadactl.KarmadaConfig, opts *options.Options) error { +func run(ctx context.Context, opts *options.Options) error { klog.Infof("karmada-agent version: %s", version.Get()) profileflag.ListenAndServe(opts.ProfileOpts) - controlPlaneRestConfig, err := karmadaConfig.GetRestConfig(opts.KarmadaContext, opts.KarmadaKubeConfig) + controlPlaneRestConfig, err := apiclient.RestConfig(opts.KarmadaContext, opts.KarmadaKubeConfig) if err != nil { return fmt.Errorf("error building kubeconfig of karmada control plane: %w", err) } diff --git a/cmd/controller-manager/app/controllermanager.go b/cmd/controller-manager/app/controllermanager.go index e50bd50d7..15161f7e1 100644 --- a/cmd/controller-manager/app/controllermanager.go +++ b/cmd/controller-manager/app/controllermanager.go @@ -13,7 +13,6 @@ import ( "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" kubeclientset "k8s.io/client-go/kubernetes" - "k8s.io/client-go/tools/clientcmd" cliflag "k8s.io/component-base/cli/flag" "k8s.io/component-base/term" "k8s.io/klog/v2" @@ -43,7 +42,7 @@ import ( "github.com/karmada-io/karmada/pkg/dependenciesdistributor" "github.com/karmada-io/karmada/pkg/detector" "github.com/karmada-io/karmada/pkg/features" - "github.com/karmada-io/karmada/pkg/karmadactl" + "github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient" "github.com/karmada-io/karmada/pkg/resourceinterpreter" "github.com/karmada-io/karmada/pkg/sharedcli" "github.com/karmada-io/karmada/pkg/sharedcli/klogflag" @@ -603,8 +602,7 @@ func setupClusterAPIClusterDetector(mgr controllerruntime.Manager, opts *options klog.Infof("Begin to setup cluster-api cluster detector") - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) - clusterAPIRestConfig, err := karmadaConfig.GetRestConfig(opts.ClusterAPIContext, opts.ClusterAPIKubeconfig) + clusterAPIRestConfig, err := apiclient.RestConfig(opts.ClusterAPIContext, opts.ClusterAPIKubeconfig) if err != nil { klog.Fatalf("Failed to get cluster-api management cluster rest config. context: %s, kubeconfig: %s, err: %v", opts.ClusterAPIContext, opts.ClusterAPIKubeconfig, err) } @@ -615,7 +613,6 @@ func setupClusterAPIClusterDetector(mgr controllerruntime.Manager, opts *options } clusterAPIClusterDetector := &clusterapi.ClusterDetector{ - KarmadaConfig: karmadaConfig, ControllerPlaneConfig: mgr.GetConfig(), ClusterAPIConfig: clusterAPIRestConfig, ClusterAPIClient: clusterAPIClient, diff --git a/pkg/clusterdiscovery/clusterapi/clusterapi.go b/pkg/clusterdiscovery/clusterapi/clusterapi.go index 2ee8d5378..3f9e98d7c 100644 --- a/pkg/clusterdiscovery/clusterapi/clusterapi.go +++ b/pkg/clusterdiscovery/clusterapi/clusterapi.go @@ -21,6 +21,7 @@ import ( "github.com/karmada-io/karmada/pkg/karmadactl" "github.com/karmada-io/karmada/pkg/karmadactl/options" + "github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient" "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/pkg/util/fedinformer" "github.com/karmada-io/karmada/pkg/util/fedinformer/genericmanager" @@ -41,7 +42,6 @@ var ( // ClusterDetector is a cluster watcher which watched cluster object in cluster-api management cluster and reconcile the events. type ClusterDetector struct { - KarmadaConfig karmadactl.KarmadaConfig ControllerPlaneConfig *rest.Config ClusterAPIConfig *rest.Config ClusterAPIClient client.Client @@ -183,7 +183,7 @@ func (d *ClusterDetector) joinClusterAPICluster(clusterWideKey keys.ClusterWideK return err } - clusterRestConfig, err := d.KarmadaConfig.GetRestConfig("", kubeconfigPath) + clusterRestConfig, err := apiclient.RestConfig("", kubeconfigPath) if err != nil { klog.Fatalf("Failed to get cluster-api management cluster rest config. kubeconfig: %s, err: %v", kubeconfigPath, err) } diff --git a/pkg/karmadactl/addons/init/disable_option.go b/pkg/karmadactl/addons/init/disable_option.go index 9dcc5b69e..0063c6784 100644 --- a/pkg/karmadactl/addons/init/disable_option.go +++ b/pkg/karmadactl/addons/init/disable_option.go @@ -7,7 +7,7 @@ import ( "k8s.io/klog/v2" "k8s.io/utils/strings/slices" - "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils" + "github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient" ) // CommandAddonsDisableOption options for addons list. @@ -26,7 +26,7 @@ func (o *CommandAddonsDisableOption) Complete() error { return err } - o.KarmadaKubeClientSet, err = utils.NewClientSet(o.KarmadaRestConfig) + o.KarmadaKubeClientSet, err = apiclient.NewClientSet(o.KarmadaRestConfig) if err != nil { return err } diff --git a/pkg/karmadactl/addons/init/enable_option.go b/pkg/karmadactl/addons/init/enable_option.go index 88766c1f8..9a2556aae 100644 --- a/pkg/karmadactl/addons/init/enable_option.go +++ b/pkg/karmadactl/addons/init/enable_option.go @@ -11,7 +11,7 @@ import ( "k8s.io/utils/strings/slices" cmdinit "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/kubernetes" - "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils" + "github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient" ) // CommandAddonsEnableOption options for addons list. @@ -48,7 +48,7 @@ func (o *CommandAddonsEnableOption) Complete() error { return err } - o.KarmadaKubeClientSet, err = utils.NewClientSet(o.KarmadaRestConfig) + o.KarmadaKubeClientSet, err = apiclient.NewClientSet(o.KarmadaRestConfig) if err != nil { return err } @@ -84,7 +84,7 @@ func (o *CommandAddonsEnableOption) Validate(args []string) error { } // Check member kubeconfig and context is valid - memberConfig, err := utils.RestConfig(o.MemberContext, o.MemberKubeConfig) + memberConfig, err := apiclient.RestConfig(o.MemberContext, o.MemberKubeConfig) if err != nil { return fmt.Errorf("failed to get member cluster config. error: %v", err) } diff --git a/pkg/karmadactl/addons/init/global.go b/pkg/karmadactl/addons/init/global.go index f28bc4202..9725d5290 100644 --- a/pkg/karmadactl/addons/init/global.go +++ b/pkg/karmadactl/addons/init/global.go @@ -1,16 +1,12 @@ package init import ( - "os" - "path/filepath" - "github.com/spf13/pflag" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" - "k8s.io/client-go/util/homedir" aggregator "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" - "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils" + "github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient" ) // GlobalCommandOptions holds the configuration shared by the all sub-commands of `karmadactl`. @@ -48,31 +44,22 @@ func (o *GlobalCommandOptions) AddFlags(flags *pflag.FlagSet) { // Complete the conditions required to be able to run list. func (o *GlobalCommandOptions) Complete() error { - if o.KubeConfig == "" { - env := os.Getenv("KUBECONFIG") - if env != "" { - o.KubeConfig = env - } else { - o.KubeConfig = filepath.Join(homedir.HomeDir(), ".kube", "config") - } - } - - restConfig, err := utils.RestConfig(o.Context, o.KubeConfig) + restConfig, err := apiclient.RestConfig(o.Context, o.KubeConfig) if err != nil { return err } - o.KubeClientSet, err = utils.NewClientSet(restConfig) + o.KubeClientSet, err = apiclient.NewClientSet(restConfig) if err != nil { return err } - o.KarmadaRestConfig, err = utils.RestConfig(o.KarmadaContext, o.KarmadaConfig) + o.KarmadaRestConfig, err = apiclient.RestConfig(o.KarmadaContext, o.KarmadaConfig) if err != nil { return err } - o.KarmadaAggregatorClientSet, err = utils.NewAPIRegistrationClient(o.KarmadaRestConfig) + o.KarmadaAggregatorClientSet, err = apiclient.NewAPIRegistrationClient(o.KarmadaRestConfig) if err != nil { return err } diff --git a/pkg/karmadactl/cmdinit/karmada/deploy.go b/pkg/karmadactl/cmdinit/karmada/deploy.go index 6c28cac85..254ba9a39 100644 --- a/pkg/karmadactl/cmdinit/karmada/deploy.go +++ b/pkg/karmadactl/cmdinit/karmada/deploy.go @@ -26,6 +26,7 @@ import ( "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/bootstraptoken/clusterinfo" "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/options" "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils" + "github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient" tokenutil "github.com/karmada-io/karmada/pkg/karmadactl/util/bootstraptoken" ) @@ -36,12 +37,12 @@ const ( // InitKarmadaResources Initialize karmada resource func InitKarmadaResources(dir, caBase64, systemNamespace string) error { - restConfig, err := utils.RestConfig("", filepath.Join(dir, options.KarmadaKubeConfigName)) + restConfig, err := apiclient.RestConfig("", filepath.Join(dir, options.KarmadaKubeConfigName)) if err != nil { return err } - clientSet, err := utils.NewClientSet(restConfig) + clientSet, err := apiclient.NewClientSet(restConfig) if err != nil { return err } @@ -56,7 +57,7 @@ func InitKarmadaResources(dir, caBase64, systemNamespace string) error { } // New CRDsClient - crdClient, err := utils.NewCRDsClient(restConfig) + crdClient, err := apiclient.NewCRDsClient(restConfig) if err != nil { return err } @@ -110,12 +111,12 @@ func InitKarmadaResources(dir, caBase64, systemNamespace string) error { // InitKarmadaBootstrapToken create initial bootstrap token func InitKarmadaBootstrapToken(dir string) (string, error) { - restConfig, err := utils.RestConfig("", filepath.Join(dir, options.KarmadaKubeConfigName)) + restConfig, err := apiclient.RestConfig("", filepath.Join(dir, options.KarmadaKubeConfigName)) if err != nil { return "", err } - clientSet, err := utils.NewClientSet(restConfig) + clientSet, err := apiclient.NewClientSet(restConfig) if err != nil { return "", err } @@ -260,7 +261,7 @@ func initAPIService(clientSet *kubernetes.Clientset, restConfig *rest.Config, sy return err } // new apiRegistrationClient - apiRegistrationClient, err := utils.NewAPIRegistrationClient(restConfig) + apiRegistrationClient, err := apiclient.NewAPIRegistrationClient(restConfig) if err != nil { return err } diff --git a/pkg/karmadactl/cmdinit/kubernetes/deploy.go b/pkg/karmadactl/cmdinit/kubernetes/deploy.go index ec14d14f8..ab20bac76 100644 --- a/pkg/karmadactl/cmdinit/kubernetes/deploy.go +++ b/pkg/karmadactl/cmdinit/kubernetes/deploy.go @@ -7,7 +7,6 @@ import ( "net" "os" "path" - "path/filepath" "strings" "time" @@ -17,7 +16,6 @@ import ( "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" certutil "k8s.io/client-go/util/cert" - "k8s.io/client-go/util/homedir" "k8s.io/klog/v2" netutils "k8s.io/utils/net" @@ -25,6 +23,7 @@ import ( "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/karmada" "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/options" "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils" + "github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient" ) var ( @@ -44,8 +43,6 @@ var ( options.FrontProxyClientCertAndKeyName, } - defaultKubeConfig = filepath.Join(homedir.HomeDir(), ".kube", "config") - defaultEtcdImage = "etcd:3.5.3-0" defaultKubeAPIServerImage = "kube-apiserver:v1.25.2" defaultKubeControllerManagerImage = "kube-controller-manager:v1.25.2" @@ -135,24 +132,14 @@ func (i *CommandInitOption) Validate(parentCommand string) error { // Complete Initialize k8s client func (i *CommandInitOption) Complete() error { - // check config path of host kubernetes cluster - if i.KubeConfig == "" { - env := os.Getenv("KUBECONFIG") - if env != "" { - i.KubeConfig = env - } else { - i.KubeConfig = defaultKubeConfig - } - } - - restConfig, err := utils.RestConfig(i.Context, i.KubeConfig) + restConfig, err := apiclient.RestConfig(i.Context, i.KubeConfig) if err != nil { return err } i.RestConfig = restConfig klog.Infof("kubeconfig file: %s, kubernetes: %s", i.KubeConfig, restConfig.Host) - clientSet, err := utils.NewClientSet(restConfig) + clientSet, err := apiclient.NewClientSet(restConfig) if err != nil { return err } diff --git a/pkg/karmadactl/cmdinit/utils/kubeclient.go b/pkg/karmadactl/cmdinit/utils/kubeclient.go deleted file mode 100644 index 26fd95259..000000000 --- a/pkg/karmadactl/cmdinit/utils/kubeclient.go +++ /dev/null @@ -1,44 +0,0 @@ -package utils - -import ( - "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" - aggregator "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" -) - -// RestConfig Kubernetes kubeconfig -func RestConfig(context, kubeconfigPath string) (*rest.Config, error) { - pathOptions := clientcmd.NewDefaultPathOptions() - - loadingRules := *pathOptions.LoadingRules - loadingRules.ExplicitPath = kubeconfigPath - loadingRules.Precedence = pathOptions.GetLoadingPrecedence() - overrides := &clientcmd.ConfigOverrides{ - CurrentContext: context, - } - clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&loadingRules, overrides) - - restConfig, err := clientConfig.ClientConfig() - if err != nil { - return nil, err - } - - return restConfig, err -} - -// NewClientSet Kubernetes ClientSet -func NewClientSet(c *rest.Config) (*kubernetes.Clientset, error) { - return kubernetes.NewForConfig(c) -} - -// NewCRDsClient clientset ClientSet -func NewCRDsClient(c *rest.Config) (*clientset.Clientset, error) { - return clientset.NewForConfig(c) -} - -// NewAPIRegistrationClient apiregistration ClientSet -func NewAPIRegistrationClient(c *rest.Config) (*aggregator.Clientset, error) { - return aggregator.NewForConfig(c) -} diff --git a/pkg/karmadactl/config.go b/pkg/karmadactl/config.go deleted file mode 100644 index 5c58f3529..000000000 --- a/pkg/karmadactl/config.go +++ /dev/null @@ -1,54 +0,0 @@ -package karmadactl - -import ( - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/clientcmd" -) - -// KarmadaConfig provides a rest config based on the filesystem kubeconfig (via -// pathOptions) and context in order to talk to the control plane -// and the joining kubernetes cluster. -type KarmadaConfig interface { - // GetRestConfig used to get a cluster's rest config. - GetRestConfig(context, kubeconfigPath string) (*rest.Config, error) - - // GetClientConfig returns a ClientConfig from kubeconfigPath. - // If kubeconfigPath is empty, will search KUBECONFIG from default path. - // If context is not empty, the returned ClientConfig's current-context is the input context. - GetClientConfig(context, kubeconfigPath string) clientcmd.ClientConfig -} - -// karmadaConfig implements the KarmadaConfig interface. -type karmadaConfig struct { - pathOptions *clientcmd.PathOptions -} - -// NewKarmadaConfig creates a karmadaConfig for `karmadactl` commands. -func NewKarmadaConfig(pathOptions *clientcmd.PathOptions) KarmadaConfig { - return &karmadaConfig{ - pathOptions: pathOptions, - } -} - -func (a *karmadaConfig) GetRestConfig(context, kubeconfigPath string) (*rest.Config, error) { - clientConfig := a.GetClientConfig(context, kubeconfigPath) - restConfig, err := clientConfig.ClientConfig() - if err != nil { - return nil, err - } - - return restConfig, nil -} - -// GetClientConfig is a helper method to create a client config from the -// context and kubeconfig passed as arguments. -func (a *karmadaConfig) GetClientConfig(context, kubeconfigPath string) clientcmd.ClientConfig { - loadingRules := *a.pathOptions.LoadingRules - loadingRules.ExplicitPath = kubeconfigPath - loadingRules.Precedence = a.pathOptions.GetLoadingPrecedence() - overrides := &clientcmd.ConfigOverrides{ - CurrentContext: context, - } - - return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&loadingRules, overrides) -} diff --git a/pkg/karmadactl/deinit.go b/pkg/karmadactl/deinit.go index afbdaa367..6a4ffb6e7 100644 --- a/pkg/karmadactl/deinit.go +++ b/pkg/karmadactl/deinit.go @@ -12,8 +12,8 @@ import ( "k8s.io/client-go/kubernetes" "k8s.io/kubectl/pkg/util/templates" - "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils" "github.com/karmada-io/karmada/pkg/karmadactl/util" + "github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient" ) const ( @@ -84,25 +84,12 @@ func NewCmdDeInit(parentCommand string) *cobra.Command { // Complete the conditions required to be able to run deinit. func (o *CommandDeInitOption) Complete() error { - if o.KubeConfig == "" { - env := os.Getenv("KUBECONFIG") - if env != "" { - o.KubeConfig = env - } else { - o.KubeConfig = defaultKubeConfig - } - } - - if !Exists(o.KubeConfig) { - return ErrEmptyConfig - } - - restConfig, err := utils.RestConfig(o.Context, o.KubeConfig) + restConfig, err := apiclient.RestConfig(o.Context, o.KubeConfig) if err != nil { return err } - o.KubeClientSet, err = utils.NewClientSet(restConfig) + o.KubeClientSet, err = apiclient.NewClientSet(restConfig) if err != nil { return err } diff --git a/pkg/karmadactl/get.go b/pkg/karmadactl/get.go index a8d471f1c..7ad39c111 100644 --- a/pkg/karmadactl/get.go +++ b/pkg/karmadactl/get.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "io" - "os" "sort" "strings" "sync" @@ -973,14 +972,6 @@ func (g *CommandGetOptions) setColumnDefinition(table *metav1.Table) { } } -// Exists determine if path exists -func Exists(path string) bool { - if _, err := os.Stat(path); err != nil { - return os.IsExist(err) - } - return true -} - // skipPrinter allows conditionally suppressing object output via the output field. // table objects are suppressed by setting their Rows to nil (allowing column definitions to propagate to the delegate). // non-table objects are suppressed by not calling the delegate at all. diff --git a/pkg/karmadactl/get_flags.go b/pkg/karmadactl/get_flags.go deleted file mode 100644 index 897340536..000000000 --- a/pkg/karmadactl/get_flags.go +++ /dev/null @@ -1,350 +0,0 @@ -/* - Copyright 2018 The Kubernetes Authors. - Copy From: https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/kubectl/pkg/cmd/get/get_flags.go - Change: ConfigFlags struct add CaBundle fields, toRawKubeConfigLoader method modify new loadRules and overrides, remove AddFlags function. -*/ - -package karmadactl - -import ( - "os" - "path/filepath" - "regexp" - "strings" - "sync" - "time" - - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/client-go/discovery" - diskcached "k8s.io/client-go/discovery/cached/disk" - "k8s.io/client-go/rest" - "k8s.io/client-go/restmapper" - "k8s.io/client-go/tools/clientcmd" - clientcmdapi "k8s.io/client-go/tools/clientcmd/api" - "k8s.io/client-go/util/homedir" -) - -var ( - defaultKubeConfig = filepath.Join(homedir.HomeDir(), ".kube", "config") - defaultCacheDir = filepath.Join(homedir.HomeDir(), ".kube", "cache") - // ErrEmptyConfig is the error message to be displayed if the configuration info is missing or incomplete - ErrEmptyConfig = clientcmd.NewEmptyConfigError( - `Missing or incomplete configuration info. Please point to an existing, complete config file: - 1. Via the command-line flag --kubeconfig - 2. Via the KUBECONFIG environment variable - 3. In your home directory as ~/.kube/config - -To view or setup config directly use the 'config' command.`) -) - -// RESTClientGetter is an interface that the ConfigFlags describe to provide an easier way to mock for commands -// and eliminate the direct coupling to a struct type. Users may wish to duplicate this type in their own packages -// as per the golang type overlapping. -type RESTClientGetter interface { - // ToRESTConfig returns restconfig - ToRESTConfig() (*rest.Config, error) - // ToDiscoveryClient returns discovery client - ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) - // ToRESTMapper returns a restmapper - ToRESTMapper() (meta.RESTMapper, error) - // ToRawKubeConfigLoader return kubeconfig loader as-is - ToRawKubeConfigLoader() clientcmd.ClientConfig -} - -type clientConfig struct { - defaultClientConfig clientcmd.ClientConfig -} - -func (c *clientConfig) RawConfig() (clientcmdapi.Config, error) { - config, err := c.defaultClientConfig.RawConfig() - // replace client-go's ErrEmptyConfig error with our custom, more verbose version - if clientcmd.IsEmptyConfig(err) { - return config, ErrEmptyConfig - } - return config, err -} - -func (c *clientConfig) ClientConfig() (*rest.Config, error) { - config, err := c.defaultClientConfig.ClientConfig() - // replace client-go's ErrEmptyConfig error with our custom, more verbose version - if clientcmd.IsEmptyConfig(err) { - return config, ErrEmptyConfig - } - return config, err -} - -func (c *clientConfig) Namespace() (string, bool, error) { - namespace, ok, err := c.defaultClientConfig.Namespace() - // replace client-go's ErrEmptyConfig error with our custom, more verbose version - if clientcmd.IsEmptyConfig(err) { - return namespace, ok, ErrEmptyConfig - } - return namespace, ok, err -} - -func (c *clientConfig) ConfigAccess() clientcmd.ConfigAccess { - return c.defaultClientConfig.ConfigAccess() -} - -var _ RESTClientGetter = &ConfigFlags{} - -// ConfigFlags composes the set of values necessary -// for obtaining a REST client config -type ConfigFlags struct { - CaBundle *string - - // Default cache director - CacheDir *string - // Path to the kubeconfig file to use for CLI requests. - KubeConfig *string - - // The name of the kubeconfig cluster to use - ClusterName *string - // The name of the kubeconfig user to use - AuthInfoName *string - // The name of the kubeconfig context to use - Context *string - // If present, the namespace scope for this CLI request - Namespace *string - // The address and port of the Kubernetes API server - APIServer *string - // Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used - TLSServerName *string - // If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure - Insecure *bool - // Path to a client certificate file for TLS - CertFile *string - // Path to a client key file for TLS - KeyFile *string - // Path to a cert file for the certificate authority - CAFile *string - // Bearer token for authentication to the API server - BearerToken *string - Impersonate *string - ImpersonateGroup *[]string - Username *string - Password *string - // The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. - Timeout *string - // If non-nil, wrap config function can transform the Config - // before it is returned in ToRESTConfig function. - WrapConfigFn func(*rest.Config) *rest.Config - - clientConfig clientcmd.ClientConfig - lock sync.Mutex - // If set to true, will use persistent client config and - // propagate the config to the places that need it, rather than - // loading the config multiple times - usePersistentConfig bool - // Allows increasing burst used for discovery, this is useful - // in clusters with many registered resources - discoveryBurst int -} - -// ToRESTConfig implements RESTClientGetter. -// Returns a REST client configuration based on a provided path -// to a .kubeconfig file, loading rules, and config flag overrides. -// Expects the AddFlags method to have been called. If WrapConfigFn -// is non-nil this function can transform config before return. -func (f *ConfigFlags) ToRESTConfig() (*rest.Config, error) { - c, err := f.ToRawKubeConfigLoader().ClientConfig() - if err != nil { - return nil, err - } - if f.WrapConfigFn != nil { - return f.WrapConfigFn(c), nil - } - return c, nil -} - -// ToRawKubeConfigLoader binds config flag values to config overrides -// Returns an interactive clientConfig if the password flag is enabled, -// or a non-interactive clientConfig otherwise. -func (f *ConfigFlags) ToRawKubeConfigLoader() clientcmd.ClientConfig { - if f.usePersistentConfig { - return f.toRawKubePersistentConfigLoader() - } - return f.toRawKubeConfigLoader() -} - -//nolint:gocyclo -func (f *ConfigFlags) toRawKubeConfigLoader() clientcmd.ClientConfig { - //loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() - loadingRules := &clientcmd.ClientConfigLoadingRules{} - // use the standard defaults for this client command - // DEPRECATED: remove and replace with something more accurate - loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig - - if f.KubeConfig != nil { - loadingRules.ExplicitPath = *f.KubeConfig - } - - clusterOverrides := clientcmd.ClusterDefaults - if f.CaBundle != nil { - clusterOverrides.CertificateAuthorityData = []byte(*f.CaBundle) - } - - overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clusterOverrides} - - // bind auth info flag values to overrides - if f.CertFile != nil { - overrides.AuthInfo.ClientCertificate = *f.CertFile - } - if f.KeyFile != nil { - overrides.AuthInfo.ClientKey = *f.KeyFile - } - if f.BearerToken != nil { - overrides.AuthInfo.Token = *f.BearerToken - } - - // bind cluster flags - if f.APIServer != nil { - overrides.ClusterInfo.Server = *f.APIServer - } - if f.TLSServerName != nil { - overrides.ClusterInfo.TLSServerName = *f.TLSServerName - } - if f.CAFile != nil { - overrides.ClusterInfo.CertificateAuthority = *f.CAFile - } - if f.Insecure != nil { - overrides.ClusterInfo.InsecureSkipTLSVerify = *f.Insecure - } - - // bind context flags - if f.Context != nil { - overrides.CurrentContext = *f.Context - } - if f.ClusterName != nil { - overrides.Context.Cluster = *f.ClusterName - } - if f.AuthInfoName != nil { - overrides.Context.AuthInfo = *f.AuthInfoName - } - if f.Namespace != nil { - overrides.Context.Namespace = *f.Namespace - } - - if f.Timeout != nil { - overrides.Timeout = *f.Timeout - } - - // we only have an interactive prompt when a password is allowed - if f.Password == nil { - return &clientConfig{clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)} - } - return &clientConfig{clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, overrides, os.Stdin)} -} - -// toRawKubePersistentConfigLoader binds config flag values to config overrides -// Returns a persistent clientConfig for propagation. -func (f *ConfigFlags) toRawKubePersistentConfigLoader() clientcmd.ClientConfig { - f.lock.Lock() - defer f.lock.Unlock() - - if f.clientConfig == nil { - f.clientConfig = f.toRawKubeConfigLoader() - } - - return f.clientConfig -} - -// ToDiscoveryClient implements RESTClientGetter. -// Expects the AddFlags method to have been called. -// Returns a CachedDiscoveryInterface using a computed RESTConfig. -func (f *ConfigFlags) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { - config, err := f.ToRESTConfig() - if err != nil { - return nil, err - } - - // The more groups you have, the more discovery requests you need to make. - // given 25 groups (our groups + a few custom resources) with one-ish version each, discovery needs to make 50 requests - // double it just so we don't end up here again for a while. This config is only used for discovery. - config.Burst = f.discoveryBurst - - cacheDir := defaultCacheDir - - // retrieve a user-provided value for the "cache-dir" - // override httpCacheDir and discoveryCacheDir if user-value is given. - if f.CacheDir != nil { - cacheDir = *f.CacheDir - } - httpCacheDir := filepath.Join(cacheDir, "http") - discoveryCacheDir := computeDiscoverCacheDir(filepath.Join(cacheDir, "discovery"), config.Host) - - return diskcached.NewCachedDiscoveryClientForConfig(config, discoveryCacheDir, httpCacheDir, time.Duration(10*time.Minute)) -} - -// ToRESTMapper returns a mapper. -func (f *ConfigFlags) ToRESTMapper() (meta.RESTMapper, error) { - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return nil, err - } - - mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) - expander := restmapper.NewShortcutExpander(mapper, discoveryClient) - return expander, nil -} - -// WithDeprecatedPasswordFlag enables the username and password config flags -func (f *ConfigFlags) WithDeprecatedPasswordFlag() *ConfigFlags { - f.Username = stringptr("") - f.Password = stringptr("") - return f -} - -// WithDiscoveryBurst sets the RESTClient burst for discovery. -func (f *ConfigFlags) WithDiscoveryBurst(discoveryBurst int) *ConfigFlags { - f.discoveryBurst = discoveryBurst - return f -} - -// NewConfigFlags returns ConfigFlags with default values set -func NewConfigFlags(usePersistentConfig bool) *ConfigFlags { - impersonateGroup := []string{} - insecure := false - - return &ConfigFlags{ - Insecure: &insecure, - Timeout: stringptr("0"), - KubeConfig: stringptr(""), - - CacheDir: stringptr(defaultCacheDir), - ClusterName: stringptr(""), - AuthInfoName: stringptr(""), - Context: stringptr(""), - Namespace: stringptr(""), - APIServer: stringptr(""), - TLSServerName: stringptr(""), - CertFile: stringptr(""), - KeyFile: stringptr(""), - CAFile: stringptr(""), - BearerToken: stringptr(""), - Impersonate: stringptr(""), - ImpersonateGroup: &impersonateGroup, - - usePersistentConfig: usePersistentConfig, - // The more groups you have, the more discovery requests you need to make. - // given 25 groups (our groups + a few custom resources) with one-ish version each, discovery needs to make 50 requests - // double it just so we don't end up here again for a while. This config is only used for discovery. - discoveryBurst: 100, - } -} - -func stringptr(val string) *string { - return &val -} - -// overlyCautiousIllegalFileCharacters matches characters that *might* not be supported. Windows is really restrictive, so this is really restrictive -var overlyCautiousIllegalFileCharacters = regexp.MustCompile(`[^(\w/\.)]`) - -// computeDiscoverCacheDir takes the parentDir and the host and comes up with a "usually non-colliding" name. -func computeDiscoverCacheDir(parentDir, host string) string { - // strip the optional scheme from host if its there: - schemelessHost := strings.Replace(strings.Replace(host, "https://", "", 1), "http://", "", 1) - // now do a simple collapse of non-AZ09 characters. Collisions are possible but unlikely. Even if we do collide the problem is short lived - safeHost := overlyCautiousIllegalFileCharacters.ReplaceAllString(schemelessHost, "_") - return filepath.Join(parentDir, safeHost) -} diff --git a/pkg/karmadactl/join.go b/pkg/karmadactl/join.go index 1fb28bc78..3d2328948 100644 --- a/pkg/karmadactl/join.go +++ b/pkg/karmadactl/join.go @@ -15,7 +15,8 @@ import ( "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" - karmadactlutil "github.com/karmada-io/karmada/pkg/karmadactl/util" + cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util" + "github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient" "github.com/karmada-io/karmada/pkg/util" ) @@ -29,7 +30,7 @@ var ( ) // NewCmdJoin defines the `join` command that registers a cluster. -func NewCmdJoin(karmadaConfig KarmadaConfig, parentCommand string) *cobra.Command { +func NewCmdJoin(f cmdutil.Factory, parentCommand string) *cobra.Command { opts := CommandJoinOption{} cmd := &cobra.Command{ @@ -46,26 +47,27 @@ func NewCmdJoin(karmadaConfig KarmadaConfig, parentCommand string) *cobra.Comman if err := opts.Validate(args); err != nil { return err } - if err := RunJoin(karmadaConfig, opts); err != nil { + if err := RunJoin(f, opts); err != nil { return err } return nil }, Annotations: map[string]string{ - karmadactlutil.TagCommandGroup: karmadactlutil.GroupClusterRegistration, + cmdutil.TagCommandGroup: cmdutil.GroupClusterRegistration, }, } flags := cmd.Flags() opts.AddFlags(flags) + flags.StringVar(defaultConfigFlags.KubeConfig, "kubeconfig", *defaultConfigFlags.KubeConfig, "Path to the kubeconfig file to use for CLI requests.") + flags.StringVar(defaultConfigFlags.Context, "karmada-context", *defaultConfigFlags.Context, "The name of the kubeconfig context to use") + return cmd } // CommandJoinOption holds all command options. type CommandJoinOption struct { - options.GlobalCommandOptions - // ClusterNamespace holds the namespace name where the member cluster secrets are stored. ClusterNamespace string @@ -126,8 +128,6 @@ func (j *CommandJoinOption) Validate(args []string) error { // AddFlags adds flags to the specified FlagSet. func (j *CommandJoinOption) AddFlags(flags *pflag.FlagSet) { - j.GlobalCommandOptions.AddFlags(flags) - flags.StringVar(&j.ClusterNamespace, "cluster-namespace", options.DefaultKarmadaClusterNamespace, "Namespace in the control plane where member cluster secrets are stored.") flags.StringVar(&j.ClusterContext, "cluster-context", "", @@ -141,19 +141,19 @@ func (j *CommandJoinOption) AddFlags(flags *pflag.FlagSet) { } // RunJoin is the implementation of the 'join' command. -func RunJoin(karmadaConfig KarmadaConfig, opts CommandJoinOption) error { +func RunJoin(f cmdutil.Factory, opts CommandJoinOption) error { klog.V(1).Infof("joining cluster. cluster name: %s", opts.ClusterName) klog.V(1).Infof("joining cluster. cluster namespace: %s", opts.ClusterNamespace) // Get control plane karmada-apiserver client - controlPlaneRestConfig, err := karmadaConfig.GetRestConfig(opts.KarmadaContext, opts.KubeConfig) + controlPlaneRestConfig, err := f.ToRawKubeConfigLoader().ClientConfig() if err != nil { return fmt.Errorf("failed to get control plane rest config. context: %s, kube-config: %s, error: %v", - opts.KarmadaContext, opts.KubeConfig, err) + *defaultConfigFlags.Context, *defaultConfigFlags.KubeConfig, err) } // Get cluster config - clusterConfig, err := karmadaConfig.GetRestConfig(opts.ClusterContext, opts.ClusterKubeConfig) + clusterConfig, err := apiclient.RestConfig(opts.ClusterContext, opts.ClusterKubeConfig) if err != nil { return fmt.Errorf("failed to get joining cluster config. error: %v", err) } diff --git a/pkg/karmadactl/karmadactl.go b/pkg/karmadactl/karmadactl.go index 1db4309cb..0ec945537 100644 --- a/pkg/karmadactl/karmadactl.go +++ b/pkg/karmadactl/karmadactl.go @@ -8,7 +8,6 @@ import ( "github.com/spf13/cobra" "github.com/spf13/pflag" "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/client-go/tools/clientcmd" apiserverflag "k8s.io/component-base/cli/flag" "k8s.io/klog/v2" "k8s.io/kubectl/pkg/util/templates" @@ -54,7 +53,6 @@ func NewKarmadaCtlCommand(cmdUse, parentCommand string) *cobra.Command { // Prevent klog errors about logging before parsing. _ = flag.CommandLine.Parse(nil) - karmadaConfig := NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) f := util.NewFactory(defaultConfigFlags) ioStreams := genericclioptions.IOStreams{In: os.Stdin, Out: os.Stdout, ErrOut: os.Stderr} groups := templates.CommandGroups{ @@ -70,8 +68,8 @@ func NewKarmadaCtlCommand(cmdUse, parentCommand string) *cobra.Command { cmdinit.NewCmdInit(parentCommand), NewCmdDeInit(parentCommand), addons.NewCommandAddons(parentCommand), - NewCmdJoin(karmadaConfig, parentCommand), - NewCmdUnjoin(karmadaConfig, parentCommand), + NewCmdJoin(f, parentCommand), + NewCmdUnjoin(f, parentCommand), NewCmdToken(f, parentCommand, ioStreams), NewCmdRegister(parentCommand), }, diff --git a/pkg/karmadactl/options/global.go b/pkg/karmadactl/options/global.go index 27101ea05..e9a66f7a5 100644 --- a/pkg/karmadactl/options/global.go +++ b/pkg/karmadactl/options/global.go @@ -1,29 +1,9 @@ package options -import ( - "time" - - "github.com/spf13/pflag" -) +import "time" // DefaultKarmadaClusterNamespace defines the default namespace where the member cluster secrets are stored. 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. - KubeConfig string - - // ClusterContext is the name of the cluster context in control plane KUBECONFIG file. - // Default value is the current-context. - KarmadaContext string -} - -// AddFlags adds flags to the specified FlagSet. -func (o *GlobalCommandOptions) AddFlags(flags *pflag.FlagSet) { - flags.StringVar(&o.KubeConfig, "kubeconfig", "", "Path to the control plane kubeconfig file.") - flags.StringVar(&o.KarmadaContext, "karmada-context", "", "Name of the cluster context in control plane kubeconfig file.") -} diff --git a/pkg/karmadactl/register.go b/pkg/karmadactl/register.go index 91c2149d7..0912efe6f 100644 --- a/pkg/karmadactl/register.go +++ b/pkg/karmadactl/register.go @@ -38,6 +38,7 @@ import ( "github.com/karmada-io/karmada/pkg/karmadactl/cmdinit/utils" "github.com/karmada-io/karmada/pkg/karmadactl/options" cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util" + "github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient" tokenutil "github.com/karmada-io/karmada/pkg/karmadactl/util/bootstraptoken" karmadautil "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/pkg/util/lifted/pubkeypin" @@ -242,20 +243,7 @@ func (o *CommandRegisterOption) Complete(args []string) error { } o.BootstrapToken.APIServerEndpoint = args[0] - if o.KubeConfig == "" { - env := os.Getenv("KUBECONFIG") - if env != "" { - o.KubeConfig = env - } else { - o.KubeConfig = defaultKubeConfig - } - } - - if !Exists(o.KubeConfig) { - return ErrEmptyConfig - } - - restConfig, err := utils.RestConfig(o.Context, o.KubeConfig) + restConfig, err := apiclient.RestConfig(o.Context, o.KubeConfig) if err != nil { return err } @@ -276,7 +264,7 @@ func (o *CommandRegisterOption) Complete(args []string) error { o.memberClusterEndpoint = restConfig.Host - o.memberClusterClient, err = utils.NewClientSet(restConfig) + o.memberClusterClient, err = apiclient.NewClientSet(restConfig) if err != nil { return err } diff --git a/pkg/karmadactl/unjoin.go b/pkg/karmadactl/unjoin.go index bff342bc3..01b7bec70 100644 --- a/pkg/karmadactl/unjoin.go +++ b/pkg/karmadactl/unjoin.go @@ -17,7 +17,8 @@ import ( karmadaclientset "github.com/karmada-io/karmada/pkg/generated/clientset/versioned" "github.com/karmada-io/karmada/pkg/karmadactl/options" - karmadactlutil "github.com/karmada-io/karmada/pkg/karmadactl/util" + cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util" + "github.com/karmada-io/karmada/pkg/karmadactl/util/apiclient" "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/pkg/util/names" ) @@ -37,7 +38,7 @@ var ( ) // NewCmdUnjoin defines the `unjoin` command that removes registration of a cluster from control plane. -func NewCmdUnjoin(karmadaConfig KarmadaConfig, parentCommand string) *cobra.Command { +func NewCmdUnjoin(f cmdutil.Factory, parentCommand string) *cobra.Command { opts := CommandUnjoinOption{} cmd := &cobra.Command{ @@ -54,26 +55,27 @@ func NewCmdUnjoin(karmadaConfig KarmadaConfig, parentCommand string) *cobra.Comm if err := opts.Validate(args); err != nil { return err } - if err := RunUnjoin(karmadaConfig, opts); err != nil { + if err := RunUnjoin(f, opts); err != nil { return err } return nil }, Annotations: map[string]string{ - karmadactlutil.TagCommandGroup: karmadactlutil.GroupClusterRegistration, + cmdutil.TagCommandGroup: cmdutil.GroupClusterRegistration, }, } flags := cmd.Flags() opts.AddFlags(flags) + flags.StringVar(defaultConfigFlags.KubeConfig, "kubeconfig", *defaultConfigFlags.KubeConfig, "Path to the kubeconfig file to use for CLI requests.") + flags.StringVar(defaultConfigFlags.Context, "karmada-context", *defaultConfigFlags.Context, "The name of the kubeconfig context to use") + return cmd } // CommandUnjoinOption holds all command options. type CommandUnjoinOption struct { - options.GlobalCommandOptions - // ClusterNamespace holds namespace where the member cluster secrets are stored ClusterNamespace string @@ -126,8 +128,6 @@ func (j *CommandUnjoinOption) Validate(args []string) error { // AddFlags adds flags to the specified FlagSet. func (j *CommandUnjoinOption) AddFlags(flags *pflag.FlagSet) { - j.GlobalCommandOptions.AddFlags(flags) - flags.StringVar(&j.ClusterNamespace, "cluster-namespace", options.DefaultKarmadaClusterNamespace, "Namespace in the control plane where member cluster secrets are stored.") flags.StringVar(&j.ClusterContext, "cluster-context", "", "Context name of cluster in kubeconfig. Only works when there are multiple contexts in the kubeconfig.") @@ -140,22 +140,22 @@ func (j *CommandUnjoinOption) AddFlags(flags *pflag.FlagSet) { } // RunUnjoin is the implementation of the 'unjoin' command. -func RunUnjoin(karmadaConfig KarmadaConfig, opts CommandUnjoinOption) error { +func RunUnjoin(f cmdutil.Factory, opts CommandUnjoinOption) error { klog.V(1).Infof("unjoining cluster. cluster name: %s", opts.ClusterName) klog.V(1).Infof("unjoining cluster. cluster namespace: %s", opts.ClusterNamespace) // Get control plane kube-apiserver client - controlPlaneRestConfig, err := karmadaConfig.GetRestConfig(opts.KarmadaContext, opts.KubeConfig) + controlPlaneRestConfig, err := f.ToRawKubeConfigLoader().ClientConfig() if err != nil { klog.Errorf("failed to get control plane rest config. context: %s, kube-config: %s, error: %v", - opts.KarmadaContext, opts.KubeConfig, err) + defaultConfigFlags.Context, defaultConfigFlags.KubeConfig, err) return err } var clusterConfig *rest.Config if opts.ClusterKubeConfig != "" { // Get cluster config - clusterConfig, err = karmadaConfig.GetRestConfig(opts.ClusterContext, opts.ClusterKubeConfig) + clusterConfig, err = apiclient.RestConfig(opts.ClusterContext, opts.ClusterKubeConfig) if err != nil { klog.V(1).Infof("failed to get unjoining cluster config. error: %v", err) return err diff --git a/pkg/karmadactl/util/apiclient/apiclient.go b/pkg/karmadactl/util/apiclient/apiclient.go new file mode 100644 index 000000000..d9b374d99 --- /dev/null +++ b/pkg/karmadactl/util/apiclient/apiclient.go @@ -0,0 +1,81 @@ +package apiclient + +import ( + "os" + "path/filepath" + + "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" + "k8s.io/client-go/kubernetes" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/util/homedir" + aggregator "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset" +) + +var ( + defaultKubeConfig = filepath.Join(homedir.HomeDir(), ".kube", "config") + + // ErrEmptyConfig is the error message to be displayed if the configuration info is missing or incomplete + ErrEmptyConfig = clientcmd.NewEmptyConfigError( + `Missing or incomplete configuration info. Please point to an existing, complete config file: + 1. Via the command-line flag --kubeconfig + 2. Via the KUBECONFIG environment variable + 3. In your home directory as ~/.kube/config +`) +) + +// RestConfig is to create a rest config from the context and kubeconfig passed as arguments. +func RestConfig(context, kubeconfigPath string) (*rest.Config, error) { + if kubeconfigPath == "" { + env := os.Getenv("KUBECONFIG") + if env != "" { + kubeconfigPath = env + } else { + kubeconfigPath = defaultKubeConfig + } + } + + if !Exists(kubeconfigPath) { + return nil, ErrEmptyConfig + } + + pathOptions := clientcmd.NewDefaultPathOptions() + + loadingRules := *pathOptions.LoadingRules + loadingRules.ExplicitPath = kubeconfigPath + loadingRules.Precedence = pathOptions.GetLoadingPrecedence() + overrides := &clientcmd.ConfigOverrides{ + CurrentContext: context, + } + clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(&loadingRules, overrides) + + restConfig, err := clientConfig.ClientConfig() + if err != nil { + return nil, err + } + + return restConfig, err +} + +// NewClientSet is to create a kubernetes ClientSet +func NewClientSet(c *rest.Config) (*kubernetes.Clientset, error) { + return kubernetes.NewForConfig(c) +} + +// NewCRDsClient is to create a clientset ClientSet +func NewCRDsClient(c *rest.Config) (*clientset.Clientset, error) { + return clientset.NewForConfig(c) +} + +// NewAPIRegistrationClient is to create an apiregistration ClientSet +func NewAPIRegistrationClient(c *rest.Config) (*aggregator.Clientset, error) { + return aggregator.NewForConfig(c) +} + +// Exists determine if path exists +func Exists(path string) bool { + if _, err := os.Stat(path); err != nil { + return os.IsExist(err) + } + return true +} diff --git a/test/e2e/aggregatedapi_test.go b/test/e2e/aggregatedapi_test.go index 54f9f0a4a..512bae78f 100644 --- a/test/e2e/aggregatedapi_test.go +++ b/test/e2e/aggregatedapi_test.go @@ -11,12 +11,14 @@ import ( rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/rand" + "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/klog/v2" "github.com/karmada-io/karmada/pkg/karmadactl" "github.com/karmada-io/karmada/pkg/karmadactl/options" + cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util" "github.com/karmada-io/karmada/test/e2e/framework" "github.com/karmada-io/karmada/test/helper" ) @@ -34,6 +36,7 @@ var _ = framework.SerialDescribe("Aggregated Kubernetes API Endpoint testing", f var tomClusterRoleBinding *rbacv1.ClusterRoleBinding var tomClusterRoleOnMember *rbacv1.ClusterRole var tomClusterRoleBindingOnMember *rbacv1.ClusterRoleBinding + var f cmdutil.Factory var ( clusterName string @@ -41,7 +44,6 @@ var _ = framework.SerialDescribe("Aggregated Kubernetes API Endpoint testing", f kubeConfigPath string clusterContext string controlPlane string - karmadaConfig karmadactl.KarmadaConfig secretStoreNamespace string ) @@ -52,9 +54,11 @@ var _ = framework.SerialDescribe("Aggregated Kubernetes API Endpoint testing", f kubeConfigPath = fmt.Sprintf("%s/.kube/%s.config", homeDir, clusterName) clusterContext = fmt.Sprintf("kind-%s", clusterName) controlPlane = fmt.Sprintf("%s-control-plane", clusterName) - karmadaConfig = karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) - secretStoreNamespace = "test-" + rand.String(RandomStrLength) + + defaultConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag().WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) + defaultConfigFlags.Context = &karmadaContext + f = cmdutil.NewFactory(defaultConfigFlags) }) ginkgo.BeforeEach(func() { @@ -74,27 +78,20 @@ var _ = framework.SerialDescribe("Aggregated Kubernetes API Endpoint testing", f ginkgo.BeforeEach(func() { ginkgo.By(fmt.Sprintf("Joinning cluster: %s", clusterName), func() { opts := karmadactl.CommandJoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: secretStoreNamespace, ClusterName: clusterName, ClusterContext: clusterContext, ClusterKubeConfig: kubeConfigPath, } - err := karmadactl.RunJoin(karmadaConfig, opts) + err := karmadactl.RunJoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) }) ginkgo.AfterEach(func() { ginkgo.By(fmt.Sprintf("Unjoinning cluster: %s", clusterName), func() { - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) opts := karmadactl.CommandUnjoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: secretStoreNamespace, ClusterName: clusterName, @@ -102,7 +99,7 @@ var _ = framework.SerialDescribe("Aggregated Kubernetes API Endpoint testing", f ClusterKubeConfig: kubeConfigPath, Wait: 5 * options.DefaultKarmadactlCommandDuration, } - err := karmadactl.RunUnjoin(karmadaConfig, opts) + err := karmadactl.RunUnjoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) }) diff --git a/test/e2e/federatedresourcequota_test.go b/test/e2e/federatedresourcequota_test.go index 0d8f51bb2..836ace2af 100644 --- a/test/e2e/federatedresourcequota_test.go +++ b/test/e2e/federatedresourcequota_test.go @@ -10,11 +10,12 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/rand" - "k8s.io/client-go/tools/clientcmd" + "k8s.io/cli-runtime/pkg/genericclioptions" policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" "github.com/karmada-io/karmada/pkg/karmadactl" "github.com/karmada-io/karmada/pkg/karmadactl/options" + cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util" "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/test/e2e/framework" "github.com/karmada-io/karmada/test/helper" @@ -23,11 +24,16 @@ import ( var _ = ginkgo.Describe("FederatedResourceQuota auto-provision testing", func() { var frqNamespace, frqName string var federatedResourceQuota *policyv1alpha1.FederatedResourceQuota + var f cmdutil.Factory ginkgo.BeforeEach(func() { frqNamespace = testNamespace frqName = federatedResourceQuotaPrefix + rand.String(RandomStrLength) federatedResourceQuota = helper.NewFederatedResourceQuota(frqNamespace, frqName) + + defaultConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag().WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) + defaultConfigFlags.Context = &karmadaContext + f = cmdutil.NewFactory(defaultConfigFlags) }) ginkgo.Context("create a federatedResourceQuota", func() { @@ -81,11 +87,7 @@ var _ = ginkgo.Describe("FederatedResourceQuota auto-provision testing", func() ginkgo.AfterEach(func() { ginkgo.By(fmt.Sprintf("Unjoinning cluster: %s", clusterName), func() { - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) opts := karmadactl.CommandUnjoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: "karmada-cluster", ClusterName: clusterName, @@ -93,7 +95,7 @@ var _ = ginkgo.Describe("FederatedResourceQuota auto-provision testing", func() ClusterKubeConfig: kubeConfigPath, Wait: 5 * options.DefaultKarmadactlCommandDuration, } - err := karmadactl.RunUnjoin(karmadaConfig, opts) + err := karmadactl.RunUnjoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) }) @@ -112,18 +114,14 @@ var _ = ginkgo.Describe("FederatedResourceQuota auto-provision testing", func() ginkgo.It("federatedResourceQuota should be propagated to new joined clusters", func() { ginkgo.By(fmt.Sprintf("Joinning cluster: %s", clusterName), func() { - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) opts := karmadactl.CommandJoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: "karmada-cluster", ClusterName: clusterName, ClusterContext: clusterContext, ClusterKubeConfig: kubeConfigPath, } - err := karmadactl.RunJoin(karmadaConfig, opts) + err := karmadactl.RunJoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) diff --git a/test/e2e/karmadactl_test.go b/test/e2e/karmadactl_test.go index 70a93f72f..d82b9b42e 100644 --- a/test/e2e/karmadactl_test.go +++ b/test/e2e/karmadactl_test.go @@ -311,7 +311,7 @@ var _ = framework.SerialDescribe("Karmadactl join/unjoin testing", ginkgo.Labels var policyName, policyNamespace string var deployment *appsv1.Deployment var policy *policyv1alpha1.PropagationPolicy - var karmadaConfig karmadactl.KarmadaConfig + var f cmdutil.Factory ginkgo.BeforeEach(func() { clusterName = "member-e2e-" + rand.String(3) @@ -336,7 +336,9 @@ var _ = framework.SerialDescribe("Karmadactl join/unjoin testing", ginkgo.Labels ClusterNames: []string{clusterName}, }, }) - karmadaConfig = karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) + defaultConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag().WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) + defaultConfigFlags.Context = &karmadaContext + f = cmdutil.NewFactory(defaultConfigFlags) }) ginkgo.BeforeEach(func() { @@ -356,16 +358,13 @@ var _ = framework.SerialDescribe("Karmadactl join/unjoin testing", ginkgo.Labels ginkgo.BeforeEach(func() { ginkgo.By(fmt.Sprintf("Joinning cluster: %s", clusterName), func() { opts := karmadactl.CommandJoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: "karmada-cluster", ClusterName: clusterName, ClusterContext: clusterContext, ClusterKubeConfig: kubeConfigPath, } - err := karmadactl.RunJoin(karmadaConfig, opts) + err := karmadactl.RunJoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) }) @@ -425,9 +424,6 @@ var _ = framework.SerialDescribe("Karmadactl join/unjoin testing", ginkgo.Labels ginkgo.By(fmt.Sprintf("Unjoinning cluster: %s", clusterName), func() { opts := karmadactl.CommandUnjoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: "karmada-cluster", ClusterName: clusterName, @@ -435,7 +431,7 @@ var _ = framework.SerialDescribe("Karmadactl join/unjoin testing", ginkgo.Labels ClusterKubeConfig: kubeConfigPath, Wait: 5 * options.DefaultKarmadactlCommandDuration, } - err := karmadactl.RunUnjoin(karmadaConfig, opts) + err := karmadactl.RunUnjoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) }) @@ -448,7 +444,6 @@ var _ = framework.SerialDescribe("Karmadactl cordon/uncordon testing", ginkgo.La var homeDir string var kubeConfigPath string var clusterContext string - var karmadaConfig karmadactl.KarmadaConfig var f cmdutil.Factory ginkgo.BeforeEach(func() { @@ -458,7 +453,6 @@ var _ = framework.SerialDescribe("Karmadactl cordon/uncordon testing", ginkgo.La controlPlane = fmt.Sprintf("%s-control-plane", clusterName) clusterContext = fmt.Sprintf("kind-%s", clusterName) - karmadaConfig = karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) defaultConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag().WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) defaultConfigFlags.Context = &karmadaContext f = cmdutil.NewFactory(defaultConfigFlags) @@ -470,18 +464,14 @@ var _ = framework.SerialDescribe("Karmadactl cordon/uncordon testing", ginkgo.La gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) ginkgo.By(fmt.Sprintf("Joinning cluster: %s", clusterName), func() { - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) opts := karmadactl.CommandJoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: "karmada-cluster", ClusterName: clusterName, ClusterContext: clusterContext, ClusterKubeConfig: kubeConfigPath, } - err := karmadactl.RunJoin(karmadaConfig, opts) + err := karmadactl.RunJoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) // When a newly joined cluster is unready at the beginning, the scheduler will ignore it. @@ -493,9 +483,6 @@ var _ = framework.SerialDescribe("Karmadactl cordon/uncordon testing", ginkgo.La ginkgo.DeferCleanup(func() { ginkgo.By(fmt.Sprintf("Unjoinning cluster: %s", clusterName), func() { opts := karmadactl.CommandUnjoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: "karmada-cluster", ClusterName: clusterName, @@ -503,7 +490,7 @@ var _ = framework.SerialDescribe("Karmadactl cordon/uncordon testing", ginkgo.La ClusterKubeConfig: kubeConfigPath, Wait: 5 * options.DefaultKarmadactlCommandDuration, } - err := karmadactl.RunUnjoin(karmadaConfig, opts) + err := karmadactl.RunUnjoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) ginkgo.By(fmt.Sprintf("Deleting clusters: %s", clusterName), func() { diff --git a/test/e2e/namespace_test.go b/test/e2e/namespace_test.go index a1b5fad5b..126df0b88 100644 --- a/test/e2e/namespace_test.go +++ b/test/e2e/namespace_test.go @@ -12,10 +12,11 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/rand" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/tools/clientcmd" + "k8s.io/cli-runtime/pkg/genericclioptions" "github.com/karmada-io/karmada/pkg/karmadactl" "github.com/karmada-io/karmada/pkg/karmadactl/options" + cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util" "github.com/karmada-io/karmada/pkg/util" "github.com/karmada-io/karmada/test/e2e/framework" "github.com/karmada-io/karmada/test/helper" @@ -24,10 +25,15 @@ import ( var _ = ginkgo.Describe("[namespace auto-provision] namespace auto-provision testing", func() { var namespaceName string var namespace *corev1.Namespace + var f cmdutil.Factory ginkgo.BeforeEach(func() { namespaceName = "karmada-e2e-ns-" + rand.String(3) namespace = helper.NewNamespace(namespaceName) + + defaultConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag().WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) + defaultConfigFlags.Context = &karmadaContext + f = cmdutil.NewFactory(defaultConfigFlags) }) ginkgo.When("create a namespace in karmada-apiserver", func() { @@ -83,29 +89,21 @@ var _ = ginkgo.Describe("[namespace auto-provision] namespace auto-provision tes ginkgo.BeforeEach(func() { ginkgo.By(fmt.Sprintf("Joinning cluster: %s", clusterName), func() { - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) opts := karmadactl.CommandJoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: "karmada-cluster", ClusterName: clusterName, ClusterContext: clusterContext, ClusterKubeConfig: kubeConfigPath, } - err := karmadactl.RunJoin(karmadaConfig, opts) + err := karmadactl.RunJoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) }) ginkgo.AfterEach(func() { ginkgo.By(fmt.Sprintf("Unjoinning cluster: %s", clusterName), func() { - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) opts := karmadactl.CommandUnjoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: "karmada-cluster", ClusterName: clusterName, @@ -113,7 +111,7 @@ var _ = ginkgo.Describe("[namespace auto-provision] namespace auto-provision tes ClusterKubeConfig: kubeConfigPath, Wait: 5 * options.DefaultKarmadactlCommandDuration, } - err := karmadactl.RunUnjoin(karmadaConfig, opts) + err := karmadactl.RunUnjoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) }) diff --git a/test/e2e/rescheduling_test.go b/test/e2e/rescheduling_test.go index f2c220659..0e5c0aa2d 100644 --- a/test/e2e/rescheduling_test.go +++ b/test/e2e/rescheduling_test.go @@ -10,7 +10,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/rand" - "k8s.io/client-go/tools/clientcmd" + "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/klog/v2" "k8s.io/utils/pointer" @@ -18,7 +18,7 @@ import ( policyv1alpha1 "github.com/karmada-io/karmada/pkg/apis/policy/v1alpha1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" "github.com/karmada-io/karmada/pkg/karmadactl" - "github.com/karmada-io/karmada/pkg/karmadactl/options" + cmdutil "github.com/karmada-io/karmada/pkg/karmadactl/util" "github.com/karmada-io/karmada/test/e2e/framework" testhelper "github.com/karmada-io/karmada/test/helper" ) @@ -31,6 +31,7 @@ var _ = ginkgo.Describe("[cluster unjoined] reschedule testing", func() { var kubeConfigPath string var controlPlane string var clusterContext string + var f cmdutil.Factory ginkgo.BeforeEach(func() { newClusterName = "member-e2e-" + rand.String(3) @@ -38,6 +39,10 @@ var _ = ginkgo.Describe("[cluster unjoined] reschedule testing", func() { kubeConfigPath = fmt.Sprintf("%s/.kube/%s.config", homeDir, newClusterName) controlPlane = fmt.Sprintf("%s-control-plane", newClusterName) clusterContext = fmt.Sprintf("kind-%s", newClusterName) + + defaultConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag().WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) + defaultConfigFlags.Context = &karmadaContext + f = cmdutil.NewFactory(defaultConfigFlags) }) ginkgo.BeforeEach(func() { @@ -84,18 +89,14 @@ var _ = ginkgo.Describe("[cluster unjoined] reschedule testing", func() { ginkgo.It("deployment reschedule testing", func() { ginkgo.By(fmt.Sprintf("Joinning cluster: %s", newClusterName), func() { - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) opts := karmadactl.CommandJoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: "karmada-cluster", ClusterName: newClusterName, ClusterContext: clusterContext, ClusterKubeConfig: kubeConfigPath, } - err := karmadactl.RunJoin(karmadaConfig, opts) + err := karmadactl.RunJoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) // wait for the current cluster status changing to true @@ -115,16 +116,11 @@ var _ = ginkgo.Describe("[cluster unjoined] reschedule testing", func() { ginkgo.By("unjoin target cluster", func() { klog.Infof("Unjoining cluster %q.", newClusterName) - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) opts := karmadactl.CommandUnjoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KubeConfig: fmt.Sprintf("%s/.kube/karmada.config", os.Getenv("HOME")), - KarmadaContext: "karmada-apiserver", - }, ClusterNamespace: "karmada-cluster", ClusterName: newClusterName, } - err := karmadactl.RunUnjoin(karmadaConfig, opts) + err := karmadactl.RunUnjoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) @@ -155,6 +151,7 @@ var _ = ginkgo.Describe("[cluster joined] reschedule testing", func() { var controlPlane string var clusterContext string var initClusterNames []string + var f cmdutil.Factory ginkgo.BeforeEach(func() { newClusterName = "member-e2e-" + rand.String(3) @@ -162,6 +159,10 @@ var _ = ginkgo.Describe("[cluster joined] reschedule testing", func() { kubeConfigPath = fmt.Sprintf("%s/.kube/%s.config", homeDir, newClusterName) controlPlane = fmt.Sprintf("%s-control-plane", newClusterName) clusterContext = fmt.Sprintf("kind-%s", newClusterName) + + defaultConfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPasswordFlag().WithDiscoveryBurst(300).WithDiscoveryQPS(50.0) + defaultConfigFlags.Context = &karmadaContext + f = cmdutil.NewFactory(defaultConfigFlags) }) ginkgo.BeforeEach(func() { @@ -173,16 +174,11 @@ var _ = ginkgo.Describe("[cluster joined] reschedule testing", func() { ginkgo.AfterEach(func() { ginkgo.By(fmt.Sprintf("Unjoin clsters: %s", newClusterName), func() { - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) opts := karmadactl.CommandUnjoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KubeConfig: fmt.Sprintf("%s/.kube/karmada.config", os.Getenv("HOME")), - KarmadaContext: "karmada-apiserver", - }, ClusterNamespace: "karmada-cluster", ClusterName: newClusterName, } - err := karmadactl.RunUnjoin(karmadaConfig, opts) + err := karmadactl.RunUnjoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) }) ginkgo.By(fmt.Sprintf("Deleting clusters: %s", newClusterName), func() { @@ -228,18 +224,14 @@ var _ = ginkgo.Describe("[cluster joined] reschedule testing", func() { }) ginkgo.By(fmt.Sprintf("Joinning cluster: %s", newClusterName)) - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) opts := karmadactl.CommandJoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: "karmada-cluster", ClusterName: newClusterName, ClusterContext: clusterContext, ClusterKubeConfig: kubeConfigPath, } - err := karmadactl.RunJoin(karmadaConfig, opts) + err := karmadactl.RunJoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) // wait for the current cluster status changing to true @@ -291,18 +283,14 @@ var _ = ginkgo.Describe("[cluster joined] reschedule testing", func() { }, pollTimeout, pollInterval).Should(gomega.BeTrue()) ginkgo.By(fmt.Sprintf("Joinning cluster: %s", newClusterName)) - karmadaConfig := karmadactl.NewKarmadaConfig(clientcmd.NewDefaultPathOptions()) opts := karmadactl.CommandJoinOption{ - GlobalCommandOptions: options.GlobalCommandOptions{ - KarmadaContext: karmadaContext, - }, DryRun: false, ClusterNamespace: "karmada-cluster", ClusterName: newClusterName, ClusterContext: clusterContext, ClusterKubeConfig: kubeConfigPath, } - err := karmadactl.RunJoin(karmadaConfig, opts) + err := karmadactl.RunJoin(f, opts) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) // wait for the current cluster status changing to true