diff --git a/pkg/cmd/get/cluster/cmd.go b/pkg/cmd/get/cluster/cmd.go index ddcf83f23..b19fa098e 100644 --- a/pkg/cmd/get/cluster/cmd.go +++ b/pkg/cmd/get/cluster/cmd.go @@ -50,5 +50,7 @@ func NewCmd(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, stream cmd.Flags().StringVar(&o.Clusterset, "clusterset", "", "ClusterSet of the clusters") + o.printer.AddFlag(cmd.Flags()) + return cmd } diff --git a/pkg/cmd/get/cluster/exec.go b/pkg/cmd/get/cluster/exec.go index 544176a9e..9e0bfd85b 100644 --- a/pkg/cmd/get/cluster/exec.go +++ b/pkg/cmd/get/cluster/exec.go @@ -11,9 +11,12 @@ import ( "k8s.io/apimachinery/pkg/runtime" clusterclientset "open-cluster-management.io/api/client/cluster/clientset/versioned" clusterapiv1 "open-cluster-management.io/api/cluster/v1" + "open-cluster-management.io/clusteradm/pkg/helpers/printer" ) func (o *Options) complete(cmd *cobra.Command, args []string) (err error) { + o.printer.Competele() + return nil } @@ -21,6 +24,12 @@ func (o *Options) validate(args []string) (err error) { if len(args) != 0 { return fmt.Errorf("there should be no argument") } + + err = o.printer.Validate() + if err != nil { + return err + } + return nil } @@ -49,12 +58,30 @@ func (o *Options) run() (err error) { return err } - table := converToTable(clusters) + o.printer.WithTreeConverter(convertToTree).WithTableConverter(converToTable) - return o.printer.PrintObj(table, o.Streams.Out) + return o.printer.Print(o.Streams, clusters) } -func converToTable(clusters *clusterapiv1.ManagedClusterList) *metav1.Table { +func convertToTree(obj runtime.Object, tree *printer.TreePrinter) *printer.TreePrinter { + if mclList, ok := obj.(*clusterapiv1.ManagedClusterList); ok { + for _, cluster := range mclList.Items { + accepted, available, version, cpu, memory, clusterset := getFileds(cluster) + mp := make(map[string]interface{}) + mp[".Accepted"] = accepted + mp[".Available"] = available + mp[".ClusterSet"] = clusterset + mp[".KubernetesVersion"] = version + mp[".Capacity.Cpu"] = cpu + mp[".Capacity.Memory"] = memory + + tree.AddFileds(cluster.Name, &mp) + } + } + return tree +} + +func converToTable(obj runtime.Object) *metav1.Table { table := &metav1.Table{ ColumnDefinitions: []metav1.TableColumnDefinition{ {Name: "Name", Type: "string"}, @@ -68,16 +95,24 @@ func converToTable(clusters *clusterapiv1.ManagedClusterList) *metav1.Table { Rows: []metav1.TableRow{}, } - for _, cluster := range clusters.Items { - row := convertRow(cluster) - table.Rows = append(table.Rows, row) - } + if mclList, ok := obj.(*clusterapiv1.ManagedClusterList); ok { + for _, cluster := range mclList.Items { + accepted, available, version, cpu, memory, clusterset := getFileds(cluster) + row := metav1.TableRow{ + Cells: []interface{}{cluster.Name, accepted, available, clusterset, cpu, memory, version}, + Object: runtime.RawExtension{Object: &cluster}, + } + table.Rows = append(table.Rows, row) + } + } return table } -func convertRow(cluster clusterapiv1.ManagedCluster) metav1.TableRow { - var available, cpu, memory, clusterset string +func getFileds(cluster clusterapiv1.ManagedCluster) (accepted bool, available, version, cpu, memory, clusterset string) { + accepted = cluster.Spec.HubAcceptsClient + + version = cluster.Status.Version.Kubernetes availableCond := meta.FindStatusCondition(cluster.Status.Conditions, clusterapiv1.ManagedClusterConditionAvailable) if availableCond != nil { @@ -96,8 +131,5 @@ func convertRow(cluster clusterapiv1.ManagedCluster) metav1.TableRow { clusterset = cluster.Labels["cluster.open-cluster-management.io/clusterset"] } - return metav1.TableRow{ - Cells: []interface{}{cluster.Name, cluster.Spec.HubAcceptsClient, available, clusterset, cpu, memory, cluster.Status.Version.Kubernetes}, - Object: runtime.RawExtension{Object: &cluster}, - } + return } diff --git a/pkg/cmd/get/cluster/options.go b/pkg/cmd/get/cluster/options.go index 428bd6996..6cfab6634 100644 --- a/pkg/cmd/get/cluster/options.go +++ b/pkg/cmd/get/cluster/options.go @@ -6,6 +6,7 @@ import ( "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/printers" genericclioptionsclusteradm "open-cluster-management.io/clusteradm/pkg/genericclioptions" + "open-cluster-management.io/clusteradm/pkg/helpers/printer" ) type Options struct { @@ -16,26 +17,28 @@ type Options struct { Streams genericclioptions.IOStreams - printer printers.ResourcePrinter + printer *printer.PrinterOption } func newOptions(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, streams genericclioptions.IOStreams) *Options { return &Options{ ClusteradmFlags: clusteradmFlags, Streams: streams, - printer: printers.NewTablePrinter(printers.PrintOptions{ - NoHeaders: false, - WithNamespace: false, - WithKind: false, - Wide: false, - ShowLabels: false, - Kind: schema.GroupKind{ - Group: "cluster.open-cluster-management.io", - Kind: "ManagedCluster", - }, - ColumnLabels: []string{}, - SortBy: "", - AllowMissingKeys: true, - }), + printer: printer.NewPrinterOption(pntOpt), } } + +var pntOpt = printers.PrintOptions{ + NoHeaders: false, + WithNamespace: false, + WithKind: false, + Wide: false, + ShowLabels: false, + Kind: schema.GroupKind{ + Group: "cluster.open-cluster-management.io", + Kind: "ManagedCluster", + }, + ColumnLabels: []string{}, + SortBy: "", + AllowMissingKeys: true, +} diff --git a/pkg/cmd/get/clusterset/cmd.go b/pkg/cmd/get/clusterset/cmd.go index 2723394b4..6295ab024 100644 --- a/pkg/cmd/get/clusterset/cmd.go +++ b/pkg/cmd/get/clusterset/cmd.go @@ -45,5 +45,7 @@ func NewCmd(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, stream }, } + o.printer.AddFlag(cmd.Flags()) + return cmd } diff --git a/pkg/cmd/get/clusterset/exec.go b/pkg/cmd/get/clusterset/exec.go index 03584c2f0..d686fef69 100644 --- a/pkg/cmd/get/clusterset/exec.go +++ b/pkg/cmd/get/clusterset/exec.go @@ -12,9 +12,22 @@ import ( "k8s.io/apimachinery/pkg/runtime" clusterclientset "open-cluster-management.io/api/client/cluster/clientset/versioned" clusterapiv1beta1 "open-cluster-management.io/api/cluster/v1beta1" + "open-cluster-management.io/clusteradm/pkg/helpers/printer" ) func (o *Options) complete(cmd *cobra.Command, args []string) (err error) { + restConfig, err := o.ClusteradmFlags.KubectlFactory.ToRESTConfig() + if err != nil { + return err + } + clusterClient, err := clusterclientset.NewForConfig(restConfig) + if err != nil { + return err + } + o.Client = clusterClient + + o.printer.Competele() + return nil } @@ -22,29 +35,31 @@ func (o *Options) validate(args []string) (err error) { if len(args) != 0 { return fmt.Errorf("there should be no argument") } - return nil -} -func (o *Options) run() (err error) { - restConfig, err := o.ClusteradmFlags.KubectlFactory.ToRESTConfig() - if err != nil { - return err - } - clusterClient, err := clusterclientset.NewForConfig(restConfig) + err = o.printer.Validate() if err != nil { return err } - clustersets, err := clusterClient.ClusterV1beta1().ManagedClusterSets().List(context.TODO(), metav1.ListOptions{}) + return nil +} + +func (o *Options) run() (err error) { + clustersets, err := o.Client.ClusterV1beta1().ManagedClusterSets().List(context.TODO(), metav1.ListOptions{}) if err != nil { return err } - bindingMap := map[string][]string{} + o.printer.WithTreeConverter(o.convertToTree).WithTableConverter(o.converToTable) + + return o.printer.Print(o.Streams, clustersets) +} - bindings, err := clusterClient.ClusterV1beta1().ManagedClusterSetBindings(metav1.NamespaceAll).List(context.TODO(), metav1.ListOptions{}) +func (o *Options) convertToTree(obj runtime.Object, tree *printer.TreePrinter) *printer.TreePrinter { + bindingMap := map[string][]string{} + bindings, err := o.Client.ClusterV1beta1().ManagedClusterSetBindings(metav1.NamespaceAll).List(context.TODO(), metav1.ListOptions{}) if err != nil { - return err + panic(err) } for _, binding := range bindings.Items { if _, ok := bindingMap[binding.Spec.ClusterSet]; !ok { @@ -54,12 +69,33 @@ func (o *Options) run() (err error) { bindingMap[binding.Spec.ClusterSet] = append(bindingMap[binding.Spec.ClusterSet], binding.Namespace) } - table := converToTable(clustersets, bindingMap) + if csList, ok := obj.(*clusterapiv1beta1.ManagedClusterSetList); ok { + for _, clusterset := range csList.Items { + boundNs, status := getFileds(clusterset, bindingMap[clusterset.Name]) + mp := make(map[string]interface{}) + mp[".BoundNamespace"] = boundNs + mp[".Status"] = status + tree.AddFileds(clusterset.Name, &mp) + } + } - return o.printer.PrintObj(table, o.Streams.Out) + return tree } -func converToTable(clustersets *clusterapiv1beta1.ManagedClusterSetList, bindingMap map[string][]string) *metav1.Table { +func (o *Options) converToTable(obj runtime.Object) *metav1.Table { + bindingMap := map[string][]string{} + bindings, err := o.Client.ClusterV1beta1().ManagedClusterSetBindings(metav1.NamespaceAll).List(context.TODO(), metav1.ListOptions{}) + if err != nil { + panic(err) + } + for _, binding := range bindings.Items { + if _, ok := bindingMap[binding.Spec.ClusterSet]; !ok { + bindingMap[binding.Spec.ClusterSet] = []string{} + } + + bindingMap[binding.Spec.ClusterSet] = append(bindingMap[binding.Spec.ClusterSet], binding.Namespace) + } + table := &metav1.Table{ ColumnDefinitions: []metav1.TableColumnDefinition{ {Name: "Name", Type: "string"}, @@ -69,25 +105,28 @@ func converToTable(clustersets *clusterapiv1beta1.ManagedClusterSetList, binding Rows: []metav1.TableRow{}, } - for _, cluster := range clustersets.Items { - bindings := bindingMap[cluster.Name] - row := convertRow(cluster, bindings) - table.Rows = append(table.Rows, row) + if csList, ok := obj.(*clusterapiv1beta1.ManagedClusterSetList); ok { + for _, clusterset := range csList.Items { + boundNs, status := getFileds(clusterset, bindingMap[clusterset.Name]) + row := metav1.TableRow{ + Cells: []interface{}{clusterset.Name, boundNs, status}, + Object: runtime.RawExtension{Object: &clusterset}, + } + + table.Rows = append(table.Rows, row) + } } return table } -func convertRow(clusterset clusterapiv1beta1.ManagedClusterSet, bindings []string) metav1.TableRow { - var status string +func getFileds(clusterset clusterapiv1beta1.ManagedClusterSet, bindings []string) (boundNs, status string) { + boundNs = strings.Join(bindings, ",") emptyCond := meta.FindStatusCondition(clusterset.Status.Conditions, clusterapiv1beta1.ManagedClusterSetConditionEmpty) if emptyCond != nil { status = string(emptyCond.Message) } - return metav1.TableRow{ - Cells: []interface{}{clusterset.Name, strings.Join(bindings, ","), status}, - Object: runtime.RawExtension{Object: &clusterset}, - } + return } diff --git a/pkg/cmd/get/clusterset/options.go b/pkg/cmd/get/clusterset/options.go index a7cb312e3..18c11c686 100644 --- a/pkg/cmd/get/clusterset/options.go +++ b/pkg/cmd/get/clusterset/options.go @@ -5,7 +5,9 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/printers" + clusterclientset "open-cluster-management.io/api/client/cluster/clientset/versioned" genericclioptionsclusteradm "open-cluster-management.io/clusteradm/pkg/genericclioptions" + "open-cluster-management.io/clusteradm/pkg/helpers/printer" ) type Options struct { @@ -14,26 +16,30 @@ type Options struct { Streams genericclioptions.IOStreams - printer printers.ResourcePrinter + printer *printer.PrinterOption + + Client *clusterclientset.Clientset } func newOptions(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, streams genericclioptions.IOStreams) *Options { return &Options{ ClusteradmFlags: clusteradmFlags, Streams: streams, - printer: printers.NewTablePrinter(printers.PrintOptions{ - NoHeaders: false, - WithNamespace: false, - WithKind: false, - Wide: false, - ShowLabels: false, - Kind: schema.GroupKind{ - Group: "cluster.open-cluster-management.io", - Kind: "ManagedCluster", - }, - ColumnLabels: []string{}, - SortBy: "", - AllowMissingKeys: true, - }), + printer: printer.NewPrinterOption(pntOpt), } } + +var pntOpt = printers.PrintOptions{ + NoHeaders: false, + WithNamespace: false, + WithKind: false, + Wide: false, + ShowLabels: false, + Kind: schema.GroupKind{ + Group: "cluster.open-cluster-management.io", + Kind: "ManagedClusterSet", + }, + ColumnLabels: []string{}, + SortBy: "", + AllowMissingKeys: true, +} diff --git a/pkg/cmd/get/work/cmd.go b/pkg/cmd/get/work/cmd.go index 168dd9337..bcedc0d7f 100644 --- a/pkg/cmd/get/work/cmd.go +++ b/pkg/cmd/get/work/cmd.go @@ -47,7 +47,9 @@ func NewCmd(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, stream }, } - cmd.Flags().StringVar(&o.cluster, "cluster", "", "Name of the managed cluster") + cmd.Flags().StringVar(&o.cluster, "cluster", "", "Names of the managed cluster") + + o.printer.AddFlag(cmd.Flags()) return cmd } diff --git a/pkg/cmd/get/work/exec.go b/pkg/cmd/get/work/exec.go index c4fcc76ee..3d9e3823f 100644 --- a/pkg/cmd/get/work/exec.go +++ b/pkg/cmd/get/work/exec.go @@ -5,7 +5,6 @@ import ( "context" "fmt" - "github.com/disiqueira/gotree" "github.com/spf13/cobra" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -17,7 +16,6 @@ import ( ) func (o *Options) complete(cmd *cobra.Command, args []string) (err error) { - if len(args) > 1 { return fmt.Errorf("can only specify one manifestwork") } @@ -26,6 +24,8 @@ func (o *Options) complete(cmd *cobra.Command, args []string) (err error) { o.workName = args[0] } + o.printer.Competele() + return nil } @@ -33,6 +33,12 @@ func (o *Options) validate() (err error) { if len(o.cluster) == 0 { return fmt.Errorf("cluster name must be specified") } + + err = o.printer.Validate() + if err != nil { + return err + } + return nil } @@ -55,29 +61,40 @@ func (o *Options) run() (err error) { return err } + var workList *workapiv1.ManifestWorkList if len(o.workName) == 0 { - workList, err := workClient.WorkV1().ManifestWorks(o.cluster).List(context.TODO(), metav1.ListOptions{}) - if err != nil { - return err - } - - table := converToTable(workList) - return o.printer.PrintObj(table, o.Streams.Out) + workList, err = workClient.WorkV1().ManifestWorks(o.cluster).List(context.TODO(), metav1.ListOptions{}) + } else { + workList, err = workClient.WorkV1().ManifestWorks(o.cluster).List(context.TODO(), metav1.ListOptions{ + FieldSelector: fmt.Sprintf("name=%s", o.workName), + }) } - - work, err := workClient.WorkV1().ManifestWorks(o.cluster).Get(context.TODO(), o.workName, metav1.GetOptions{}) if err != nil { return err } - root := gotree.New("") - printer.PrintWorkDetail(root, work) + o.printer.WithTreeConverter(convertToTree).WithTableConverter(converToTable) - fmt.Fprint(o.Streams.Out, root.Print()) - return nil + return o.printer.Print(o.Streams, workList) } -func converToTable(works *workapiv1.ManifestWorkList) *metav1.Table { +func convertToTree(obj runtime.Object, tree *printer.TreePrinter) *printer.TreePrinter { + if workList, ok := obj.(*workapiv1.ManifestWorkList); ok { + for _, work := range workList.Items { + cluster, number, applied, available := getFileds(work) + mp := make(map[string]interface{}) + mp[".Cluster"] = cluster + mp[".Number of Manifests"] = number + mp[".Applied"] = applied + mp[".Available"] = available + + tree.AddFileds(work.Name, &mp) + } + } + return tree +} + +func converToTable(obj runtime.Object) *metav1.Table { table := &metav1.Table{ ColumnDefinitions: []metav1.TableColumnDefinition{ {Name: "Name", Type: "string"}, @@ -89,16 +106,24 @@ func converToTable(works *workapiv1.ManifestWorkList) *metav1.Table { Rows: []metav1.TableRow{}, } - for _, work := range works.Items { - row := convertRow(work) - table.Rows = append(table.Rows, row) + if workList, ok := obj.(*workapiv1.ManifestWorkList); ok { + for _, work := range workList.Items { + cluster, number, applied, available := getFileds(work) + row := metav1.TableRow{ + Cells: []interface{}{work.Name, cluster, number, applied, available}, + Object: runtime.RawExtension{Object: &work}, + } + + table.Rows = append(table.Rows, row) + } } return table } -func convertRow(work workapiv1.ManifestWork) metav1.TableRow { - var applied, available string +func getFileds(work workapiv1.ManifestWork) (cluster string, number int, applied, available string) { + cluster = work.Namespace + number = len(work.Spec.Workload.Manifests) appliedCond := meta.FindStatusCondition(work.Status.Conditions, workapiv1.WorkApplied) if appliedCond != nil { @@ -110,8 +135,5 @@ func convertRow(work workapiv1.ManifestWork) metav1.TableRow { available = string(availableCond.Status) } - return metav1.TableRow{ - Cells: []interface{}{work.Name, work.Namespace, len(work.Spec.Workload.Manifests), applied, available}, - Object: runtime.RawExtension{Object: &work}, - } + return } diff --git a/pkg/cmd/get/work/options.go b/pkg/cmd/get/work/options.go index eeb311ea5..22d52c83f 100644 --- a/pkg/cmd/get/work/options.go +++ b/pkg/cmd/get/work/options.go @@ -6,6 +6,7 @@ import ( "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/printers" genericclioptionsclusteradm "open-cluster-management.io/clusteradm/pkg/genericclioptions" + "open-cluster-management.io/clusteradm/pkg/helpers/printer" ) type Options struct { @@ -18,26 +19,28 @@ type Options struct { Streams genericclioptions.IOStreams - printer printers.ResourcePrinter + printer *printer.PrinterOption } func newOptions(clusteradmFlags *genericclioptionsclusteradm.ClusteradmFlags, streams genericclioptions.IOStreams) *Options { return &Options{ ClusteradmFlags: clusteradmFlags, Streams: streams, - printer: printers.NewTablePrinter(printers.PrintOptions{ - NoHeaders: false, - WithNamespace: false, - WithKind: false, - Wide: false, - ShowLabels: false, - Kind: schema.GroupKind{ - Group: "work.open-cluster-management.io", - Kind: "ManifestWork", - }, - ColumnLabels: []string{}, - SortBy: "", - AllowMissingKeys: true, - }), + printer: printer.NewPrinterOption(pntOpt), } } + +var pntOpt = printers.PrintOptions{ + NoHeaders: false, + WithNamespace: false, + WithKind: false, + Wide: false, + ShowLabels: false, + Kind: schema.GroupKind{ + Group: "work.open-cluster-management.io", + Kind: "ManifestWork", + }, + ColumnLabels: []string{}, + SortBy: "", + AllowMissingKeys: true, +}