1/* 2Copyright 2018 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package get 18 19import ( 20 "fmt" 21 "strings" 22 23 "github.com/spf13/cobra" 24 25 "k8s.io/apimachinery/pkg/api/meta" 26 "k8s.io/apimachinery/pkg/runtime/schema" 27 "k8s.io/cli-runtime/pkg/genericclioptions" 28 "k8s.io/cli-runtime/pkg/printers" 29 "k8s.io/kubectl/pkg/util/openapi" 30) 31 32// PrintFlags composes common printer flag structs 33// used in the Get command. 34type PrintFlags struct { 35 JSONYamlPrintFlags *genericclioptions.JSONYamlPrintFlags 36 NamePrintFlags *genericclioptions.NamePrintFlags 37 CustomColumnsFlags *CustomColumnsPrintFlags 38 HumanReadableFlags *HumanPrintFlags 39 TemplateFlags *genericclioptions.KubeTemplatePrintFlags 40 41 NoHeaders *bool 42 OutputFormat *string 43} 44 45// SetKind sets the Kind option of humanreadable flags 46func (f *PrintFlags) SetKind(kind schema.GroupKind) { 47 f.HumanReadableFlags.SetKind(kind) 48} 49 50// EnsureWithNamespace ensures that humanreadable flags return 51// a printer capable of printing with a "namespace" column. 52func (f *PrintFlags) EnsureWithNamespace() error { 53 return f.HumanReadableFlags.EnsureWithNamespace() 54} 55 56// EnsureWithKind ensures that humanreadable flags return 57// a printer capable of including resource kinds. 58func (f *PrintFlags) EnsureWithKind() error { 59 return f.HumanReadableFlags.EnsureWithKind() 60} 61 62// Copy returns a copy of PrintFlags for mutation 63func (f *PrintFlags) Copy() PrintFlags { 64 printFlags := *f 65 return printFlags 66} 67 68// AllowedFormats is the list of formats in which data can be displayed 69func (f *PrintFlags) AllowedFormats() []string { 70 formats := f.JSONYamlPrintFlags.AllowedFormats() 71 formats = append(formats, f.NamePrintFlags.AllowedFormats()...) 72 formats = append(formats, f.TemplateFlags.AllowedFormats()...) 73 formats = append(formats, f.CustomColumnsFlags.AllowedFormats()...) 74 formats = append(formats, f.HumanReadableFlags.AllowedFormats()...) 75 return formats 76} 77 78// UseOpenAPIColumns modifies the output format, as well as the 79// "allowMissingKeys" option for template printers, to values 80// defined in the OpenAPI schema of a resource. 81func (f *PrintFlags) UseOpenAPIColumns(api openapi.Resources, mapping *meta.RESTMapping) error { 82 // Found openapi metadata for this resource 83 schema := api.LookupResource(mapping.GroupVersionKind) 84 if schema == nil { 85 // Schema not found, return empty columns 86 return nil 87 } 88 89 columns, found := openapi.GetPrintColumns(schema.GetExtensions()) 90 if !found { 91 // Extension not found, return empty columns 92 return nil 93 } 94 95 parts := strings.SplitN(columns, "=", 2) 96 if len(parts) < 2 { 97 return nil 98 } 99 100 allowMissingKeys := true 101 f.OutputFormat = &parts[0] 102 f.TemplateFlags.TemplateArgument = &parts[1] 103 f.TemplateFlags.AllowMissingKeys = &allowMissingKeys 104 return nil 105} 106 107// ToPrinter attempts to find a composed set of PrintFlags suitable for 108// returning a printer based on current flag values. 109func (f *PrintFlags) ToPrinter() (printers.ResourcePrinter, error) { 110 outputFormat := "" 111 if f.OutputFormat != nil { 112 outputFormat = *f.OutputFormat 113 } 114 115 noHeaders := false 116 if f.NoHeaders != nil { 117 noHeaders = *f.NoHeaders 118 } 119 f.HumanReadableFlags.NoHeaders = noHeaders 120 f.CustomColumnsFlags.NoHeaders = noHeaders 121 122 // for "get.go" we want to support a --template argument given, even when no --output format is provided 123 if f.TemplateFlags.TemplateArgument != nil && len(*f.TemplateFlags.TemplateArgument) > 0 && len(outputFormat) == 0 { 124 outputFormat = "go-template" 125 } 126 127 if p, err := f.TemplateFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) { 128 return p, err 129 } 130 131 if f.TemplateFlags.TemplateArgument != nil { 132 f.CustomColumnsFlags.TemplateArgument = *f.TemplateFlags.TemplateArgument 133 } 134 135 if p, err := f.JSONYamlPrintFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) { 136 return p, err 137 } 138 139 if p, err := f.HumanReadableFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) { 140 return p, err 141 } 142 143 if p, err := f.CustomColumnsFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) { 144 return p, err 145 } 146 147 if p, err := f.NamePrintFlags.ToPrinter(outputFormat); !genericclioptions.IsNoCompatiblePrinterError(err) { 148 return p, err 149 } 150 151 return nil, genericclioptions.NoCompatiblePrinterError{OutputFormat: &outputFormat, AllowedFormats: f.AllowedFormats()} 152} 153 154// AddFlags receives a *cobra.Command reference and binds 155// flags related to humanreadable and template printing. 156func (f *PrintFlags) AddFlags(cmd *cobra.Command) { 157 f.JSONYamlPrintFlags.AddFlags(cmd) 158 f.NamePrintFlags.AddFlags(cmd) 159 f.TemplateFlags.AddFlags(cmd) 160 f.HumanReadableFlags.AddFlags(cmd) 161 f.CustomColumnsFlags.AddFlags(cmd) 162 163 if f.OutputFormat != nil { 164 cmd.Flags().StringVarP(f.OutputFormat, "output", "o", *f.OutputFormat, fmt.Sprintf("Output format. One of: %s See custom columns [https://kubernetes.io/docs/reference/kubectl/overview/#custom-columns], golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [https://kubernetes.io/docs/reference/kubectl/jsonpath/].", strings.Join(f.AllowedFormats(), "|"))) 165 } 166 if f.NoHeaders != nil { 167 cmd.Flags().BoolVar(f.NoHeaders, "no-headers", *f.NoHeaders, "When using the default or custom-column output format, don't print headers (default print headers).") 168 } 169} 170 171// NewGetPrintFlags returns flags associated with humanreadable, 172// template, and "name" printing, with default values set. 173func NewGetPrintFlags() *PrintFlags { 174 outputFormat := "" 175 noHeaders := false 176 177 return &PrintFlags{ 178 OutputFormat: &outputFormat, 179 NoHeaders: &noHeaders, 180 181 JSONYamlPrintFlags: genericclioptions.NewJSONYamlPrintFlags(), 182 NamePrintFlags: genericclioptions.NewNamePrintFlags(""), 183 TemplateFlags: genericclioptions.NewKubeTemplatePrintFlags(), 184 185 HumanReadableFlags: NewHumanPrintFlags(), 186 CustomColumnsFlags: NewCustomColumnsPrintFlags(), 187 } 188} 189