Skip to content

Commit

Permalink
Merge pull request #2589 from helen-frank/feature/getFactory
Browse files Browse the repository at this point in the history
karmadactl get uses factory to access cluster
  • Loading branch information
karmada-bot authored Oct 21, 2022
2 parents 12d2a29 + ffb17f6 commit dbb24d3
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 98 deletions.
165 changes: 68 additions & 97 deletions pkg/karmadactl/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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]",
Expand All @@ -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
Expand All @@ -110,26 +108,25 @@ func NewCmdGet(karmadaConfig KarmadaConfig, parentCommand string, streams generi
},
}

o.GlobalCommandOptions.AddFlags(cmd.Flags())
o.PrintFlags.AddFlags(cmd)

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 := cmd.Flags()

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
Expand All @@ -148,8 +145,8 @@ type CommandGetOptions struct {

LabelSelector string
FieldSelector string
AllNamespaces bool
Namespace string
AllNamespaces bool
ExplicitNamespace bool

ServerPrint bool
Expand All @@ -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 {
Expand Down Expand Up @@ -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

Expand All @@ -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()

Expand Down Expand Up @@ -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")
}
Expand All @@ -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()
Expand All @@ -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).
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion pkg/karmadactl/karmadactl.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
},
},
{
Expand Down

0 comments on commit dbb24d3

Please sign in to comment.