From 52c8c001e80bafe9168a40ce41468ae347fef5b8 Mon Sep 17 00:00:00 2001 From: Clark Uthayakumar Date: Sat, 10 Feb 2024 01:44:31 +1000 Subject: [PATCH 1/2] custom-columns output --- cmd/get/get.go | 32 +++++++++++++++++----------- pkg/tablegenerator/tablegenerator.go | 30 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/cmd/get/get.go b/cmd/get/get.go index 36726a14..074db515 100644 --- a/cmd/get/get.go +++ b/cmd/get/get.go @@ -392,23 +392,31 @@ func handleObject(obj unstructured.Unstructured) error { } klog.V(3).Info("INFO deserializing ", obj.GetKind(), " ", obj.GetName()) var objectTable *metav1.Table - _, ok := vars.KnownResources[strings.ToLower(obj.GetKind())] - if ok { - runtimeObjectType := deserializer.RawObjectToRuntimeObject(rawObject, vars.Schema) - if err := yaml.Unmarshal(rawObject, runtimeObjectType); err != nil { - klog.V(3).Info(err, err.Error()) - } - objectTable, err = tablegenerator.InternalResourceTable(runtimeObjectType, &obj) + if strings.HasPrefix(vars.OutputStringVar, "custom-columns=") { + objectTable, err = tablegenerator.CustomColumnsTable(&obj) if err != nil { - klog.V(3).Info("INFO ", fmt.Sprintf("%s: %s, %s", err.Error(), obj.GetKind(), obj.GetAPIVersion())) klog.V(1).ErrorS(err, err.Error()) return err } } else { - objectTable, err = tablegenerator.GenerateCustomResourceTable(obj) - if err != nil { - klog.V(1).ErrorS(err, err.Error()) - return err + _, ok := vars.KnownResources[strings.ToLower(obj.GetKind())] + if ok { + runtimeObjectType := deserializer.RawObjectToRuntimeObject(rawObject, vars.Schema) + if err := yaml.Unmarshal(rawObject, runtimeObjectType); err != nil { + klog.V(3).Info(err, err.Error()) + } + objectTable, err = tablegenerator.InternalResourceTable(runtimeObjectType, &obj) + if err != nil { + klog.V(3).Info("INFO ", fmt.Sprintf("%s: %s, %s", err.Error(), obj.GetKind(), obj.GetAPIVersion())) + klog.V(1).ErrorS(err, err.Error()) + return err + } + } else { + objectTable, err = tablegenerator.GenerateCustomResourceTable(obj) + if err != nil { + klog.V(1).ErrorS(err, err.Error()) + return err + } } } diff --git a/pkg/tablegenerator/tablegenerator.go b/pkg/tablegenerator/tablegenerator.go index c07f9d20..c7003b83 100644 --- a/pkg/tablegenerator/tablegenerator.go +++ b/pkg/tablegenerator/tablegenerator.go @@ -2,6 +2,7 @@ package tablegenerator import ( "fmt" + "regexp" "sort" "strings" @@ -18,6 +19,35 @@ import ( apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" ) +func CustomColumnsTable(unstruct *unstructured.Unstructured) (*metav1.Table, error) { + // Matches .metadata.name and metadata.name formats + format := regexp.MustCompile(`^\.?([^{}]+)$`) + fieldSelectors := map[string]string{} + prefix := "custom-columns=" + table := &metav1.Table{} + args := vars.OutputStringVar[len(prefix):] + fields := strings.Split(args, ",") + + for _, field := range fields { + fieldPair := strings.Split(field, ":") + if len(fieldPair) != 2 { + return nil, fmt.Errorf("error processing column '%s': expected format :", field) + } + name, selector := fieldPair[0], fieldPair[1] + name = strings.Title(strings.ToLower(name)) + column := metav1.TableColumnDefinition{Name: name, Type: "string"} + table.ColumnDefinitions = append(table.ColumnDefinitions, column) + fieldSelectors[name] = selector + } + cells := make([]interface{}, 0) + for _, column := range table.ColumnDefinitions { + matches := format.FindStringSubmatch(fieldSelectors[column.Name]) + cells = append(cells, helpers.GetFromJsonPath(unstruct.Object, fmt.Sprintf("%s%s%s", "{.", matches[1], "}"))) + } + table.Rows = []metav1.TableRow{{Cells: cells}} + return table, nil +} + func InternalResourceTable(runtimeObject runtime.Object, unstruct *unstructured.Unstructured) (*metav1.Table, error) { resourceKind := strings.ToLower(unstruct.GetKind()) table, err := vars.TableGenerator.GenerateTable(runtimeObject, printers.GenerateOptions{Wide: vars.Wide, NoHeaders: false}) From 27ce75d2b879b9254c12b04c82716c018a71928e Mon Sep 17 00:00:00 2001 From: Clark Uthayakumar Date: Sat, 10 Feb 2024 02:42:38 +1000 Subject: [PATCH 2/2] Update docs to mention custom-columns --- cmd/get/get.go | 4 ++-- docs/subcmds/get.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/get/get.go b/cmd/get/get.go index 074db515..368b4b2f 100644 --- a/cmd/get/get.go +++ b/cmd/get/get.go @@ -74,7 +74,7 @@ var yamlData []byte var GetCmd = &cobra.Command{ Use: "get", - Short: "Get kubernetes/openshift object in tabular format or wide|yaml|json|jsonpath.", + Short: "Get kubernetes/openshift object in tabular format or wide|yaml|json|jsonpath|custom-columns.", Run: func(cmd *cobra.Command, args []string) { if len(args) == 0 { cmd.Help() @@ -117,7 +117,7 @@ func init() { GetCmd.PersistentFlags().BoolVar(&vars.NoHeaders, "no-headers", false, "When using the default or custom-column output format, don't print headers (default print headers).") GetCmd.PersistentFlags().BoolVar(&vars.ShowManagedFields, "show-managed-fields", false, "If true, show the managedFields when printing objects in JSON or YAML format.") GetCmd.PersistentFlags().BoolVarP(&vars.ShowLabelsBoolVar, "show-labels", "", false, "When printing, show all labels as the last column (default hide labels column)") - GetCmd.PersistentFlags().StringVarP(&vars.OutputStringVar, "output", "o", "", "Output format. One of: json|yaml|wide|jsonpath=...") + GetCmd.PersistentFlags().StringVarP(&vars.OutputStringVar, "output", "o", "", "Output format. One of: json|yaml|wide|jsonpath|custom-columns=...") GetCmd.PersistentFlags().StringVarP(&vars.LabelSelectorStringVar, "selector", "l", "", "selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)") } diff --git a/docs/subcmds/get.md b/docs/subcmds/get.md index fd30bbbe..0cb478c7 100644 --- a/docs/subcmds/get.md +++ b/docs/subcmds/get.md @@ -16,3 +16,4 @@ omc get pod my-pod -o yaml # Get a pod's YAML | `-o=name` | Print only the resource name and nothing else | | `-o=wide` | Output in the plain-text format with any additional information, and for pods, the node name is included | | `-o=yaml` | Output a YAML formatted API object | +| `-o=custom-columns` | Allows a user to customise the fields that are output and their corresponding header names |