Merge pull request #2589 from helen-frank/feature/getFactory
karmadactl get uses factory to access cluster
This commit is contained in:
commit
dbb24d3b62
|
@ -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,
|
||||
|
|
|
@ -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),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue