diff --git a/ctl/authz/authz.go b/ctl/authz/authz.go index 7998af4f1..fbb58ee07 100644 --- a/ctl/authz/authz.go +++ b/ctl/authz/authz.go @@ -113,11 +113,11 @@ func NewStatusCmd() *cobra.Command { } // Prepare a slice of podStatuses. We can pre-allocate since we know how many pods we'll check. - type podStatus struct { - Pod string - Status string + type PodStatus struct { + Pod string `json:"pod"` + Status string `json:"status"` } - statuses := make([]podStatus, 0, len(podNames)) + statuses := make([]PodStatus, 0, len(podNames)) // Collect the status for each pod. for _, podName := range podNames { @@ -126,7 +126,14 @@ func NewStatusCmd() *cobra.Command { log.Errorf("failed to get authz status for pod %s: %v", podName, err) continue } - statuses = append(statuses, podStatus{Pod: podName, Status: status}) + statuses = append(statuses, PodStatus{Pod: podName, Status: status}) + } + + if handled, err := utils.PrintOutput(cmd, statuses); err != nil { + log.Errorf("failed to print output: %v", err) + os.Exit(1) + } else if handled { + return } // Output the results in a table format. diff --git a/ctl/common/common.go b/ctl/common/common.go index b804bafc1..5de415fa0 100644 --- a/ctl/common/common.go +++ b/ctl/common/common.go @@ -38,6 +38,8 @@ func GetRootCommand() *cobra.Command { }, } + rootCmd.PersistentFlags().StringP("output", "o", "", "Output format. One of: json|yaml") + rootCmd.AddCommand(logcmd.NewCmd()) rootCmd.AddCommand(dump.NewCmd()) rootCmd.AddCommand(waypoint.NewCmd()) diff --git a/ctl/log/log.go b/ctl/log/log.go index 61253e3c1..fdcdd77ec 100644 --- a/ctl/log/log.go +++ b/ctl/log/log.go @@ -87,26 +87,40 @@ func GetJson(url string, val any) error { return nil } -func GetLoggerNames(url string) { +func GetLoggerNames(cmd *cobra.Command, url string) { var loggerNames []string if err := GetJson(url, &loggerNames); err != nil { log.Errorf("failed to get logger names: %v", err) return } + if handled, err := utils.PrintOutput(cmd, loggerNames); err != nil { + log.Errorf("failed to print output: %v", err) + os.Exit(1) + } else if handled { + return + } + fmt.Printf("Existing Loggers:\n") for _, logger := range loggerNames { fmt.Printf("\t%s\n", logger) } } -func GetLoggerLevel(url string) { +func GetLoggerLevel(cmd *cobra.Command, url string) { var loggerInfo LoggerInfo if err := GetJson(url, &loggerInfo); err != nil { log.Errorf("failed to get logger level: %v", err) return } + if handled, err := utils.PrintOutput(cmd, loggerInfo); err != nil { + log.Errorf("failed to print output: %v", err) + os.Exit(1) + } else if handled { + return + } + fmt.Printf("Logger Name: %s\n", loggerInfo.Name) fmt.Printf("Logger Level: %s\n", loggerInfo.Level) } @@ -182,9 +196,9 @@ func RunGetOrSetLoggerLevel(cmd *cobra.Command, args []string) { if setFlag == "" { if len(args) >= 2 { url += fmt.Sprintf("?name=%s", args[1]) - GetLoggerLevel(url) + GetLoggerLevel(cmd, url) } else { - GetLoggerNames(url) + GetLoggerNames(cmd, url) } } else { SetLoggerLevel(url, setFlag) diff --git a/ctl/secret/secret.go b/ctl/secret/secret.go index 58b788ce8..817961258 100644 --- a/ctl/secret/secret.go +++ b/ctl/secret/secret.go @@ -85,7 +85,7 @@ kmeshctl secret create --key=$(echo -n "{36-character user-defined key here}" | kmeshctl secret get`, Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { - GetSecret() + GetSecret(cmd) }, } @@ -198,7 +198,7 @@ func CreateOrUpdateSecret(cmd *cobra.Command, args []string) { } } -func GetSecret() { +func GetSecret(cmd *cobra.Command) { secret, err := clientset.Kube().CoreV1().Secrets(utils.KmeshNamespace).Get(context.TODO(), SecretName, metav1.GetOptions{}) if err != nil { if apierrors.IsNotFound(err) { @@ -234,6 +234,13 @@ func GetSecret() { Length: ipSecKey.Length, } + if handled, err := utils.PrintOutput(cmd, displayKey); err != nil { + log.Errorf("failed to print output: %v", err) + os.Exit(1) + } else if handled { + return + } + displayData, err := json.MarshalIndent(displayKey, "", " ") if err != nil { log.Errorf("failed to marshal display data: %v", err) diff --git a/ctl/utils/printer.go b/ctl/utils/printer.go new file mode 100644 index 000000000..3bd9e1335 --- /dev/null +++ b/ctl/utils/printer.go @@ -0,0 +1,43 @@ +package utils + +import ( + "encoding/json" + "fmt" + + "github.com/spf13/cobra" + "sigs.k8s.io/yaml" +) + +// PrintOutput checks if the global --output (-o) flag is set on the command. +// If it is set to "json" or "yaml", it marshals the data appropriately, prints it to stdout, +// and returns true (indicating to the caller that default table/text formatting can be skipped). +// If no output format is specified, it returns false. +func PrintOutput(cmd *cobra.Command, data interface{}) (bool, error) { + outputFlag, err := cmd.Flags().GetString("output") + if err != nil { + // Flag might not be defined on some commands, default to normal output + return false, nil + } + + switch outputFlag { + case "json": + b, err := json.MarshalIndent(data, "", " ") + if err != nil { + return false, fmt.Errorf("failed to marshal json: %w", err) + } + fmt.Println(string(b)) + return true, nil + case "yaml", "yml": + b, err := yaml.Marshal(data) + if err != nil { + return false, fmt.Errorf("failed to marshal yaml: %w", err) + } + fmt.Print(string(b)) // yaml.Marshal already appends a newline + return true, nil + case "": + return false, nil + default: + // Unsupported output format, fallback to default or throw error + return false, fmt.Errorf("unsupported output format: %s", outputFlag) + } +}