diff --git a/pkg/karmadactl/get.go b/pkg/karmadactl/get.go index 5a5e88b2b..bda6af4b6 100644 --- a/pkg/karmadactl/get.go +++ b/pkg/karmadactl/get.go @@ -32,12 +32,10 @@ import ( "k8s.io/kubectl/pkg/util/interrupt" "k8s.io/kubectl/pkg/util/templates" utilpointer "k8s.io/utils/pointer" - "sigs.k8s.io/controller-runtime/pkg/client" clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" workv1alpha2 "github.com/karmada-io/karmada/pkg/apis/work/v1alpha2" karmadaclientset "github.com/karmada-io/karmada/pkg/generated/clientset/versioned" - "github.com/karmada-io/karmada/pkg/karmadactl/options" "github.com/karmada-io/karmada/pkg/karmadactl/util" "github.com/karmada-io/karmada/pkg/util/gclient" "github.com/karmada-io/karmada/pkg/util/helper" @@ -61,31 +59,31 @@ var ( getExample = templates.Examples(` # List all pods in ps output format %[1]s get pods - + # List all pods in ps output format with more information (such as node name) %[1]s get pods -o wide - + # List all pods of member1 cluster in ps output format %[1]s get pods -C member1 - + # List a single replicasets controller with specified NAME in ps output format %[1]s get replicasets nginx - + # List deployments in JSON output format, in the "v1" version of the "apps" API group %[1]s get deployments.v1.apps -o json - + # Return only the phase value of the specified resource %[1]s get -o template deployment/nginx -C member1 --template={{.spec.replicas}} - + # List all replication controllers and services together in ps output format %[1]s get rs,services - + # List one or more resources by their type and names %[1]s get rs/nginx-cb87b6d88 service/kubernetes`) ) // NewCmdGet New get command -func NewCmdGet(karmadaConfig KarmadaConfig, parentCommand string, streams genericclioptions.IOStreams) *cobra.Command { +func NewCmdGet(f util.Factory, parentCommand string, streams genericclioptions.IOStreams) *cobra.Command { o := NewCommandGetOptions(streams) cmd := &cobra.Command{ Use: "get [NAME | -l label | -n namespace]", @@ -94,13 +92,13 @@ func NewCmdGet(karmadaConfig KarmadaConfig, parentCommand string, streams generi DisableFlagsInUseLine: true, Example: fmt.Sprintf(getExample, parentCommand), RunE: func(cmd *cobra.Command, args []string) error { - if err := o.Complete(karmadaConfig); err != nil { + if err := o.Complete(f); err != nil { return err } if err := o.Validate(cmd); err != nil { return err } - if err := o.Run(karmadaConfig, cmd, args); err != nil { + if err := o.Run(f, cmd, args); err != nil { return err } return nil @@ -110,26 +108,25 @@ func NewCmdGet(karmadaConfig KarmadaConfig, parentCommand string, streams generi }, } - o.GlobalCommandOptions.AddFlags(cmd.Flags()) o.PrintFlags.AddFlags(cmd) + flags := cmd.Flags() - cmd.Flags().StringVarP(&o.Namespace, "namespace", "n", o.Namespace, "-n=namespace or -n namespace") - cmd.Flags().StringVarP(&o.LabelSelector, "labels", "l", "", "-l=label or -l label") - cmd.Flags().StringSliceVarP(&o.Clusters, "clusters", "C", []string{}, "-C=member1,member2") - cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.") - cmd.Flags().BoolVar(&o.IgnoreNotFound, "ignore-not-found", o.IgnoreNotFound, "If the requested object does not exist the command will return exit code 0.") - cmd.Flags().BoolVarP(&o.Watch, "watch", "w", o.Watch, "After listing/getting the requested object, watch for changes. Uninitialized objects are excluded if no object name is provided.") - cmd.Flags().BoolVar(&o.WatchOnly, "watch-only", o.WatchOnly, "Watch for changes to the requested object(s), without listing/getting first.") - cmd.Flags().BoolVar(&o.OutputWatchEvents, "output-watch-events", o.OutputWatchEvents, "Output watch event objects when --watch or --watch-only is used. Existing objects are output as initial ADDED events.") + flags.StringVarP(&o.LabelSelector, "labels", "l", "", "-l=label or -l label") + flags.StringSliceVarP(&o.Clusters, "clusters", "C", []string{}, "-C=member1,member2") + flags.BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If present, list the requested object(s) across all namespaces. Namespace in current context is ignored even if specified with --namespace.") + flags.BoolVar(&o.IgnoreNotFound, "ignore-not-found", o.IgnoreNotFound, "If the requested object does not exist the command will return exit code 0.") + flags.BoolVarP(&o.Watch, "watch", "w", o.Watch, "After listing/getting the requested object, watch for changes. Uninitialized objects are excluded if no object name is provided.") + flags.BoolVar(&o.WatchOnly, "watch-only", o.WatchOnly, "Watch for changes to the requested object(s), without listing/getting first.") + flags.BoolVar(&o.OutputWatchEvents, "output-watch-events", o.OutputWatchEvents, "Output watch event objects when --watch or --watch-only is used. Existing objects are output as initial ADDED events.") + 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") + flags.StringVarP(defaultConfigFlags.Namespace, "namespace", "n", *defaultConfigFlags.Namespace, "If present, the namespace scope for this CLI request") return cmd } // CommandGetOptions contains the input to the get command. type CommandGetOptions struct { - // global flags - options.GlobalCommandOptions - Clusters []string PrintFlags *get.PrintFlags @@ -148,8 +145,8 @@ type CommandGetOptions struct { LabelSelector string FieldSelector string - AllNamespaces bool Namespace string + AllNamespaces bool ExplicitNamespace bool ServerPrint bool @@ -173,16 +170,13 @@ func NewCommandGetOptions(streams genericclioptions.IOStreams) *CommandGetOption } // Complete takes the command arguments and infers any remaining options. -func (g *CommandGetOptions) Complete(karmadaConfig KarmadaConfig) error { +func (g *CommandGetOptions) Complete(f util.Factory) error { newScheme := gclient.NewSchema() - - if g.Namespace == "" { - namespace, _, err := karmadaConfig.GetClientConfig(g.KarmadaContext, g.KubeConfig).Namespace() - if err != nil { - return err - } - g.Namespace = namespace + namespace, _, err := f.ToRawKubeConfigLoader().Namespace() + if err != nil { + return err } + g.Namespace = namespace templateArg := "" if g.PrintFlags.TemplateFlags != nil && g.PrintFlags.TemplateFlags.TemplateArgument != nil { @@ -265,7 +259,7 @@ type OtherPrint struct { } // Run performs the get operation. -func (g *CommandGetOptions) Run(karmadaConfig KarmadaConfig, cmd *cobra.Command, args []string) error { +func (g *CommandGetOptions) Run(f util.Factory, cmd *cobra.Command, args []string) error { mux := sync.Mutex{} var wg sync.WaitGroup @@ -282,22 +276,35 @@ func (g *CommandGetOptions) Run(karmadaConfig KarmadaConfig, cmd *cobra.Command, g.ServerPrint = false } - clusterInfos := make(map[string]*ClusterInfo) RBInfo = make(map[string]*OtherPrint) - karmadaRestConfig, err := clusterInfoInit(g, karmadaConfig, clusterInfos) + gclient, err := f.KarmadaClientSet() if err != nil { return err } + clusterInfos, err := getClusterInKarmadaForClient(gclient) + if err != nil { + return fmt.Errorf("method getClusterInKarmadaForClient get cluster info in karmada failed, err is: %w", err) + } + + if err := g.getRBInKarmada(gclient); err != nil { + return err + } + + if len(g.Clusters) <= 0 { + for c := range clusterInfos { + g.Clusters = append(g.Clusters, c) + } + } + wg.Add(len(g.Clusters)) for idx := range g.Clusters { - err = g.setClusterProxyInfo(karmadaRestConfig, g.Clusters[idx], clusterInfos) + memberFactory, err := f.FactoryForMemberCluster(g.Clusters[idx]) if err != nil { return err } - f := getFactory(g.Clusters[idx], clusterInfos, "") - go g.getObjInfo(&wg, &mux, f, g.Clusters[idx], &objs, &watchObjs, &allErrs, args) + go g.getObjInfo(&wg, &mux, memberFactory, g.Clusters[idx], &objs, &watchObjs, &allErrs, args) } wg.Wait() @@ -405,7 +412,7 @@ func (g *CommandGetOptions) printObjs(objs []Obj, allErrs *[]error, args []strin func (g *CommandGetOptions) printIfNotFindResource(written int, allErrs *[]error, allResourcesNamespaced bool) { if written == 0 && !g.IgnoreNotFound && len(*allErrs) == 0 { if allResourcesNamespaced { - fmt.Fprintf(g.ErrOut, "No resources found in %s namespace.\n", g.Namespace) + fmt.Fprintf(g.ErrOut, "No resources found in %s namespace.\n", *defaultConfigFlags.Namespace) } else { fmt.Fprintln(g.ErrOut, "No resources found") } @@ -422,7 +429,8 @@ func (g *CommandGetOptions) checkPrintWithNamespace(mapping *meta.RESTMapping) b // getObjInfo get obj info in member cluster func (g *CommandGetOptions) getObjInfo(wg *sync.WaitGroup, mux *sync.Mutex, f cmdutil.Factory, - cluster string, objs *[]Obj, watchObjs *[]WatchObj, allErrs *[]error, args []string) { + cluster string, objs *[]Obj, watchObjs *[]WatchObj, allErrs *[]error, args []string, +) { defer wg.Done() restClient, err := f.RESTClient() @@ -437,7 +445,6 @@ func (g *CommandGetOptions) getObjInfo(wg *sync.WaitGroup, mux *sync.Mutex, f cm *allErrs = append(*allErrs, fmt.Errorf("cluster(%s) is inaccessible, please check authorization or network", cluster)) return } - r := f.NewBuilder(). Unstructured(). NamespaceParam(g.Namespace).DefaultNamespace().AllNamespaces(g.AllNamespaces). @@ -867,29 +874,6 @@ type ClusterInfo struct { ClusterSyncMode clusterv1alpha1.ClusterSyncMode } -func clusterInfoInit(g *CommandGetOptions, karmadaConfig KarmadaConfig, clusterInfos map[string]*ClusterInfo) (*rest.Config, error) { - karmadaRestConfig, err := karmadaConfig.GetRestConfig(g.KarmadaContext, g.KubeConfig) - if err != nil { - return nil, fmt.Errorf("failed to get control plane rest config. context: %s, kube-config: %s, error: %v", - g.KarmadaContext, g.KubeConfig, err) - } - - if err := getClusterInKarmada(karmadaRestConfig, clusterInfos); err != nil { - return nil, fmt.Errorf("method getClusterInKarmada get cluster info in karmada failed, err is: %w", err) - } - - if err := g.getRBInKarmada(g.Namespace, karmadaRestConfig); err != nil { - return nil, err - } - - if len(g.Clusters) <= 0 { - for c := range clusterInfos { - g.Clusters = append(g.Clusters, c) - } - } - return karmadaRestConfig, nil -} - func getFactory(clusterName string, clusterInfos map[string]*ClusterInfo, namespace string) cmdutil.Factory { kubeConfigFlags := NewConfigFlags(true).WithDeprecatedPasswordFlag() // Build member cluster kubeConfigFlags @@ -920,27 +904,21 @@ func (g *CommandGetOptions) transformRequests(req *rest.Request) { }, ",")) } -func (g *CommandGetOptions) getRBInKarmada(namespace string, config *rest.Config) error { - rbList := &workv1alpha2.ResourceBindingList{} - crbList := &workv1alpha2.ClusterResourceBindingList{} - - gClient, err := gclient.NewForConfig(config) - if err != nil { - return err - } +func (g *CommandGetOptions) getRBInKarmada(gclient karmadaclientset.Interface) error { + var rbList *workv1alpha2.ResourceBindingList + var crbList *workv1alpha2.ClusterResourceBindingList + var err error if !g.AllNamespaces { - err = gClient.List(context.TODO(), rbList, &client.ListOptions{ - Namespace: namespace, - }) + rbList, err = gclient.WorkV1alpha2().ResourceBindings(*defaultConfigFlags.Namespace).List(context.TODO(), metav1.ListOptions{}) } else { - err = gClient.List(context.TODO(), rbList, &client.ListOptions{}) + rbList, err = gclient.WorkV1alpha2().ResourceBindings("").List(context.TODO(), metav1.ListOptions{}) } if err != nil { return err } - if err = gClient.List(context.TODO(), crbList, &client.ListOptions{}); err != nil { + if crbList, err = gclient.WorkV1alpha2().ClusterResourceBindings().List(context.TODO(), metav1.ListOptions{}); err != nil { return err } @@ -971,28 +949,22 @@ func (g *CommandGetOptions) getRBInKarmada(namespace string, config *rest.Config return nil } -// setClusterProxyInfo set proxy information of cluster -func (g *CommandGetOptions) setClusterProxyInfo(karmadaRestConfig *rest.Config, name string, clusterInfos map[string]*ClusterInfo) error { - clusterClient := karmadaclientset.NewForConfigOrDie(karmadaRestConfig).ClusterV1alpha1().Clusters() - - // check if the cluster exists in the Karmada control plane - _, err := clusterClient.Get(context.TODO(), name, metav1.GetOptions{}) +// getClusterInKarmadaForClient get cluster info in karmada cluster +func getClusterInKarmadaForClient(gclient karmadaclientset.Interface) (map[string]*ClusterInfo, error) { + clusterList, err := gclient.ClusterV1alpha1().Clusters().List(context.TODO(), metav1.ListOptions{}) if err != nil { - return err + return nil, err } - clusterInfos[name].APIEndpoint = karmadaRestConfig.Host + fmt.Sprintf(proxyURL, name) - clusterInfos[name].KubeConfig = g.KubeConfig - clusterInfos[name].Context = g.KarmadaContext - if clusterInfos[name].KubeConfig == "" { - env := os.Getenv("KUBECONFIG") - if env != "" { - clusterInfos[name].KubeConfig = env - } else { - clusterInfos[name].KubeConfig = defaultKubeConfig + clusterInfos := make(map[string]*ClusterInfo, len(clusterList.Items)) + for i := range clusterList.Items { + cluster := &ClusterInfo{ + APIEndpoint: clusterList.Items[i].Spec.APIEndpoint, + ClusterSyncMode: clusterList.Items[i].Spec.SyncMode, } + clusterInfos[clusterList.Items[i].GetName()] = cluster } - return nil + return clusterInfos, nil } // getClusterInKarmada get cluster info in karmada cluster @@ -1005,7 +977,6 @@ func getClusterInKarmada(client *rest.Config, clusterInfos map[string]*ClusterIn if err = gClient.List(context.TODO(), clusterList); err != nil { return err } - for i := range clusterList.Items { cluster := &ClusterInfo{ APIEndpoint: clusterList.Items[i].Spec.APIEndpoint, diff --git a/pkg/karmadactl/karmadactl.go b/pkg/karmadactl/karmadactl.go index a821e0e42..cd4374c02 100644 --- a/pkg/karmadactl/karmadactl.go +++ b/pkg/karmadactl/karmadactl.go @@ -61,7 +61,7 @@ func NewKarmadaCtlCommand(cmdUse, parentCommand string) *cobra.Command { { Message: "Basic Commands:", Commands: []*cobra.Command{ - NewCmdGet(karmadaConfig, parentCommand, ioStreams), + NewCmdGet(f, parentCommand, ioStreams), }, }, {