output.go 6.6 KB

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