k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/kubeadm/app/util/output/output.go (about)

     1  /*
     2  Copyright 2019 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package output
    18  
    19  import (
    20  	"fmt"
    21  	"io"
    22  	"strings"
    23  
    24  	"github.com/spf13/cobra"
    25  
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/cli-runtime/pkg/genericclioptions"
    28  	"k8s.io/cli-runtime/pkg/printers"
    29  )
    30  
    31  const (
    32  	// TextOutput describes the plain text output
    33  	TextOutput = "text"
    34  
    35  	// JSONOutput describes the JSON output
    36  	JSONOutput = "json"
    37  
    38  	// YAMLOutput describes the YAML output
    39  	YAMLOutput = "yaml"
    40  )
    41  
    42  // TextPrintFlags is an interface to handle custom text output
    43  type TextPrintFlags interface {
    44  	ToPrinter(outputFormat string) (Printer, error)
    45  }
    46  
    47  // PrintFlags composes common printer flag structs
    48  // used across kubeadm commands, and provides a method
    49  // of retrieving a known printer based on flag values provided.
    50  type PrintFlags struct {
    51  	// JSONYamlPrintFlags provides default flags necessary for json/yaml printing.
    52  	JSONYamlPrintFlags *genericclioptions.JSONYamlPrintFlags
    53  	// KubeTemplatePrintFlags composes print flags that provide both a JSONPath and a go-template printer.
    54  	KubeTemplatePrintFlags *genericclioptions.KubeTemplatePrintFlags
    55  	// TextPrintFlags provides default flags necessary for kubeadm text printing.
    56  	TextPrintFlags TextPrintFlags
    57  	// TypeSetterPrinter is an implementation of ResourcePrinter that wraps another printer with types set on the objects
    58  	TypeSetterPrinter *printers.TypeSetterPrinter
    59  	// OutputFormat contains currently set output format
    60  	OutputFormat *string
    61  }
    62  
    63  // AllowedFormats returns a list of allowed output formats
    64  func (pf *PrintFlags) AllowedFormats() []string {
    65  	ret := []string{TextOutput}
    66  	ret = append(ret, pf.JSONYamlPrintFlags.AllowedFormats()...)
    67  	ret = append(ret, pf.KubeTemplatePrintFlags.AllowedFormats()...)
    68  
    69  	return ret
    70  }
    71  
    72  // ToPrinter receives an outputFormat and returns a printer capable of
    73  // handling format printing.
    74  // Returns error if the specified outputFormat does not match supported formats.
    75  func (pf *PrintFlags) ToPrinter() (Printer, error) {
    76  	outputFormat := ""
    77  	if pf.OutputFormat != nil {
    78  		outputFormat = *pf.OutputFormat
    79  	}
    80  
    81  	if pf.TextPrintFlags != nil {
    82  		if p, err := pf.TextPrintFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) {
    83  			return p, err
    84  		}
    85  	}
    86  
    87  	if pf.JSONYamlPrintFlags != nil {
    88  		if p, err := pf.JSONYamlPrintFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) {
    89  			return NewResourcePrinterWrapper(pf.TypeSetterPrinter.WrapToPrinter(p, err))
    90  		}
    91  	}
    92  
    93  	if pf.KubeTemplatePrintFlags != nil {
    94  		if p, err := pf.KubeTemplatePrintFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) {
    95  			return NewResourcePrinterWrapper(pf.TypeSetterPrinter.WrapToPrinter(p, err))
    96  		}
    97  	}
    98  
    99  	return nil, genericclioptions.NoCompatiblePrinterError{OutputFormat: pf.OutputFormat, AllowedFormats: pf.AllowedFormats()}
   100  }
   101  
   102  // AddFlags receives a *cobra.Command reference and binds
   103  // flags related to Kubeadm printing to it
   104  func (pf *PrintFlags) AddFlags(cmd *cobra.Command) {
   105  	pf.JSONYamlPrintFlags.AddFlags(cmd)
   106  	pf.KubeTemplatePrintFlags.AddFlags(cmd)
   107  	cmd.Flags().StringVarP(pf.OutputFormat, "output", "o", *pf.OutputFormat, fmt.Sprintf("Output format. One of: %s.", strings.Join(pf.AllowedFormats(), "|")))
   108  	cmd.Flags().StringVarP(pf.OutputFormat, "experimental-output", "", *pf.OutputFormat, fmt.Sprintf("Output format. One of: %s.", strings.Join(pf.AllowedFormats(), "|")))
   109  	_ = cmd.Flags().MarkDeprecated("experimental-output", "please use --output instead.")
   110  }
   111  
   112  // WithDefaultOutput sets a default output format if one is not provided through a flag value
   113  func (pf *PrintFlags) WithDefaultOutput(outputFormat string) *PrintFlags {
   114  	pf.OutputFormat = &outputFormat
   115  	return pf
   116  }
   117  
   118  // WithTypeSetter sets a wrapper than will surround the returned printer with a printer to type resources
   119  func (pf *PrintFlags) WithTypeSetter(scheme *runtime.Scheme) *PrintFlags {
   120  	pf.TypeSetterPrinter = printers.NewTypeSetter(scheme)
   121  	return pf
   122  }
   123  
   124  // NewOutputFlags creates new KubeadmOutputFlags
   125  func NewOutputFlags(textPrintFlags TextPrintFlags) *PrintFlags {
   126  	outputFormat := ""
   127  
   128  	pf := &PrintFlags{
   129  		OutputFormat: &outputFormat,
   130  
   131  		JSONYamlPrintFlags:     genericclioptions.NewJSONYamlPrintFlags(),
   132  		KubeTemplatePrintFlags: genericclioptions.NewKubeTemplatePrintFlags(),
   133  		TextPrintFlags:         textPrintFlags,
   134  	}
   135  
   136  	// disable deprecated --template option
   137  	pf.KubeTemplatePrintFlags.TemplateArgument = nil
   138  
   139  	return pf
   140  }
   141  
   142  // Printer is a common printing interface in Kubeadm
   143  type Printer interface {
   144  	PrintObj(obj runtime.Object, writer io.Writer) error
   145  	Fprintf(writer io.Writer, format string, args ...interface{}) (n int, err error)
   146  	Fprintln(writer io.Writer, args ...interface{}) (n int, err error)
   147  	Printf(format string, args ...interface{}) (n int, err error)
   148  	Println(args ...interface{}) (n int, err error)
   149  }
   150  
   151  // TextPrinter implements Printer interface for generic text output
   152  type TextPrinter struct {
   153  }
   154  
   155  // PrintObj is an implementation of ResourcePrinter.PrintObj that prints object
   156  func (tp *TextPrinter) PrintObj(obj runtime.Object, writer io.Writer) error {
   157  	_, err := fmt.Fprintf(writer, "%+v\n", obj)
   158  	return err
   159  }
   160  
   161  // Fprintf is a wrapper around fmt.Fprintf
   162  func (tp *TextPrinter) Fprintf(writer io.Writer, format string, args ...interface{}) (n int, err error) {
   163  	return fmt.Fprintf(writer, format, args...)
   164  }
   165  
   166  // Fprintln is a wrapper around fmt.Fprintln
   167  func (tp *TextPrinter) Fprintln(writer io.Writer, args ...interface{}) (n int, err error) {
   168  	return fmt.Fprintln(writer, args...)
   169  }
   170  
   171  // Printf is a wrapper around fmt.Printf
   172  func (tp *TextPrinter) Printf(format string, args ...interface{}) (n int, err error) {
   173  	return fmt.Printf(format, args...)
   174  }
   175  
   176  // Println is a wrapper around fmt.Printf
   177  func (tp *TextPrinter) Println(args ...interface{}) (n int, err error) {
   178  	return fmt.Println(args...)
   179  }
   180  
   181  // ResourcePrinterWrapper wraps ResourcePrinter and implements Printer interface
   182  type ResourcePrinterWrapper struct {
   183  	Printer printers.ResourcePrinter
   184  }
   185  
   186  // NewResourcePrinterWrapper creates new ResourcePrinter object
   187  func NewResourcePrinterWrapper(resourcePrinter printers.ResourcePrinter, err error) (Printer, error) {
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	return &ResourcePrinterWrapper{Printer: resourcePrinter}, nil
   192  }
   193  
   194  // PrintObj is an implementation of ResourcePrinter.PrintObj that calls underlying printer API
   195  func (rpw *ResourcePrinterWrapper) PrintObj(obj runtime.Object, writer io.Writer) error {
   196  	return rpw.Printer.PrintObj(obj, writer)
   197  }
   198  
   199  // Fprintf is an empty method to satisfy Printer interface
   200  // and silent info printing for structured output
   201  // This method is usually redefined for the text output
   202  func (rpw *ResourcePrinterWrapper) Fprintf(writer io.Writer, format string, args ...interface{}) (n int, err error) {
   203  	return 0, nil
   204  }
   205  
   206  // Fprintln is an empty method to satisfy the Printer interface
   207  // and silent info printing for structured output
   208  // This method is usually redefined for the text output
   209  func (rpw *ResourcePrinterWrapper) Fprintln(writer io.Writer, args ...interface{}) (n int, err error) {
   210  	return 0, nil
   211  }
   212  
   213  // Printf is an empty method to satisfy Printer interface
   214  // and silent info printing for structured output
   215  // This method is usually redefined for the text output
   216  func (rpw *ResourcePrinterWrapper) Printf(format string, args ...interface{}) (n int, err error) {
   217  	return 0, nil
   218  }
   219  
   220  // Println is an empty method to satisfy Printer interface
   221  // and silent info printing for structured output
   222  // This method is usually redefined for the text output
   223  func (rpw *ResourcePrinterWrapper) Println(args ...interface{}) (n int, err error) {
   224  	return 0, nil
   225  }