Merge pull request #2752 from lonelyCZ/pr-join-factory

karmadactl join/unjoin use factory to access control plane
This commit is contained in:
karmada-bot 2022-11-07 16:58:30 +08:00 committed by GitHub
commit abad935461
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 194 additions and 679 deletions

View File

@ -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)
}

View File

@ -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,

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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.

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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),
},

View File

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

View File

@ -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
}

View File

@ -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

View File

@ -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
}

View File

@ -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())
})
})

View File

@ -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())
})

View File

@ -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() {

View File

@ -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())
})
})

View File

@ -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