mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 14:37:00 +00:00
Merge pull request #46235 from droot/cmd-printer-refactor
Automatic merge from submit-queue (batch tested with PRs 46235, 44786, 46833, 46756, 46669) Get command uses print-column extn from Openapi schema **What this PR does / why we need it**: Kubectl Get command now uses metadata 'x-kubernetes-print-column' from Openapi schema to display a resource. This is to enable richer experience for non-compiled types (like service catalog API resources) in Kubectl. This functionality is currently guarded by a boolean flag "use-openapi-print-columns". **Which issue this PR fixes** *(optional, in `fixes #<issue number>(, fixes #<issue_number>, ...)` format, will close that issue when PR gets merged)*: fixes # fixes https://github.com/kubernetes/kubectl/issues/22 **Special notes for your reviewer**: **Release note**: ```release-note Get command uses OpenAPI schema to enhance display for a resource if run with flag 'use-openapi-print-columns'. An example command: kubectl get pods --use-openapi-print-columns ```
This commit is contained in:
commit
a42867f194
@ -92,6 +92,7 @@ go_library(
|
||||
"//pkg/kubectl/cmd/templates:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/editor:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
||||
"//pkg/kubectl/metricsutil:go_default_library",
|
||||
"//pkg/kubectl/plugins:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
@ -208,6 +209,7 @@ go_test(
|
||||
"//pkg/kubectl:go_default_library",
|
||||
"//pkg/kubectl/cmd/testing:go_default_library",
|
||||
"//pkg/kubectl/cmd/util:go_default_library",
|
||||
"//pkg/kubectl/cmd/util/openapi:go_default_library",
|
||||
"//pkg/kubectl/plugins:go_default_library",
|
||||
"//pkg/kubectl/resource:go_default_library",
|
||||
"//pkg/printers:go_default_library",
|
||||
@ -215,6 +217,7 @@ go_test(
|
||||
"//pkg/util/i18n:go_default_library",
|
||||
"//pkg/util/strings:go_default_library",
|
||||
"//pkg/util/term:go_default_library",
|
||||
"//vendor/github.com/go-openapi/spec:go_default_library",
|
||||
"//vendor/github.com/spf13/cobra:go_default_library",
|
||||
"//vendor/github.com/stretchr/testify/assert:go_default_library",
|
||||
"//vendor/gopkg.in/yaml.v2:go_default_library",
|
||||
|
@ -81,7 +81,7 @@ func NewCmdConfigView(out, errOut io.Writer, ConfigAccess clientcmd.ConfigAccess
|
||||
cmd.Flags().Set("output", defaultOutputFormat)
|
||||
}
|
||||
|
||||
printer, err := cmdutil.PrinterForCommand(cmd, meta.NewDefaultRESTMapper(nil, nil), latest.Scheme, nil, []runtime.Decoder{latest.Codec}, printers.PrintOptions{})
|
||||
printer, err := cmdutil.PrinterForCommand(cmd, nil, meta.NewDefaultRESTMapper(nil, nil), latest.Scheme, nil, []runtime.Decoder{latest.Codec}, printers.PrintOptions{})
|
||||
cmdutil.CheckErr(err)
|
||||
printer = printers.NewVersionedPrinter(printer, latest.Scheme, latest.ExternalVersion)
|
||||
|
||||
|
@ -164,7 +164,7 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C
|
||||
cmd.Flags().Set("output", outputFormat)
|
||||
}
|
||||
o.encoder = f.JSONEncoder()
|
||||
o.printer, err = f.PrinterForCommand(cmd, printers.PrintOptions{})
|
||||
o.printer, err = f.PrinterForCommand(cmd, nil, printers.PrintOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/spf13/cobra"
|
||||
@ -33,6 +34,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/printers"
|
||||
"k8s.io/kubernetes/pkg/util/i18n"
|
||||
@ -90,6 +92,10 @@ var (
|
||||
kubectl get all`))
|
||||
)
|
||||
|
||||
const (
|
||||
useOpenAPIPrintColumnFlagLabel = "experimental-use-openapi-print-columns"
|
||||
)
|
||||
|
||||
// NewCmdGet creates a command object for the generic "get" action, which
|
||||
// retrieves one or more resources from a server.
|
||||
func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command {
|
||||
@ -128,6 +134,7 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman
|
||||
cmd.Flags().BoolVar(&options.IgnoreNotFound, "ignore-not-found", false, "Treat \"resource not found\" as a successful retrieval.")
|
||||
cmd.Flags().StringSliceP("label-columns", "L", []string{}, "Accepts a comma separated list of labels that are going to be presented as columns. Names are case-sensitive. You can also use multiple flag options like -L label1 -L label2...")
|
||||
cmd.Flags().Bool("export", false, "If true, use 'export' for the resources. Exported resources are stripped of cluster-specific information.")
|
||||
addOpenAPIPrintColumnFlags(cmd)
|
||||
usage := "identifying the resource to get from a server."
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmdutil.AddInclude3rdPartyFlags(cmd)
|
||||
@ -219,7 +226,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
}
|
||||
info := infos[0]
|
||||
mapping := info.ResourceMapping()
|
||||
printer, err := f.PrinterForMapping(cmd, mapping, allNamespaces)
|
||||
printer, err := f.PrinterForMapping(cmd, nil, mapping, allNamespaces)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -299,7 +306,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
return err
|
||||
}
|
||||
|
||||
printer, err := f.PrinterForCommand(cmd, printers.PrintOptions{})
|
||||
printer, err := f.PrinterForCommand(cmd, nil, printers.PrintOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -418,6 +425,8 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
var lastMapping *meta.RESTMapping
|
||||
w := printers.GetNewTabWriter(out)
|
||||
|
||||
useOpenAPIPrintColumns := cmdutil.GetFlagBool(cmd, useOpenAPIPrintColumnFlagLabel)
|
||||
|
||||
if resource.MultipleTypesRequested(args) || cmdutil.MustPrintWithKinds(objs, infos, sorter) {
|
||||
showKind = true
|
||||
}
|
||||
@ -426,6 +435,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
for ix := range objs {
|
||||
var mapping *meta.RESTMapping
|
||||
var original runtime.Object
|
||||
|
||||
if sorter != nil {
|
||||
mapping = infos[sorter.OriginalPosition(ix)].Mapping
|
||||
original = infos[sorter.OriginalPosition(ix)].Object
|
||||
@ -437,7 +447,15 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
if printer != nil {
|
||||
w.Flush()
|
||||
}
|
||||
printer, err = f.PrinterForMapping(cmd, mapping, allNamespaces)
|
||||
|
||||
var outputOpts *printers.OutputOptions
|
||||
// if cmd does not specify output format and useOpenAPIPrintColumnFlagLabel flag is true,
|
||||
// then get the default output options for this mapping from OpenAPI schema.
|
||||
if !cmdSpecifiesOutputFmt(cmd) && useOpenAPIPrintColumns {
|
||||
outputOpts, _ = outputOptsForMappingFromOpenAPI(f, cmdutil.GetOpenAPICacheDir(cmd), mapping)
|
||||
}
|
||||
|
||||
printer, err = f.PrinterForMapping(cmd, outputOpts, mapping, allNamespaces)
|
||||
if err != nil {
|
||||
if !errs.Has(err.Error()) {
|
||||
errs.Insert(err.Error())
|
||||
@ -498,7 +516,13 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err := printer.PrintObj(decodedObj, w); err != nil {
|
||||
objToPrint := decodedObj
|
||||
if printer.IsGeneric() {
|
||||
// use raw object as recieved from the builder when using generic
|
||||
// printer instead of decodedObj
|
||||
objToPrint = original
|
||||
}
|
||||
if err := printer.PrintObj(objToPrint, w); err != nil {
|
||||
if !errs.Has(err.Error()) {
|
||||
errs.Insert(err.Error())
|
||||
allErrs = append(allErrs, err)
|
||||
@ -511,6 +535,59 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
|
||||
return utilerrors.NewAggregate(allErrs)
|
||||
}
|
||||
|
||||
func addOpenAPIPrintColumnFlags(cmd *cobra.Command) {
|
||||
cmd.Flags().Bool(useOpenAPIPrintColumnFlagLabel, false, "If true, use x-kubernetes-print-column metadata (if present) from openapi schema for displaying a resource.")
|
||||
// marking it deprecated so that it is hidden from usage/help text.
|
||||
cmd.Flags().MarkDeprecated(useOpenAPIPrintColumnFlagLabel, "its an experimental feature.")
|
||||
}
|
||||
|
||||
func shouldGetNewPrinterForMapping(printer printers.ResourcePrinter, lastMapping, mapping *meta.RESTMapping) bool {
|
||||
return printer == nil || lastMapping == nil || mapping == nil || mapping.Resource != lastMapping.Resource
|
||||
}
|
||||
|
||||
func cmdSpecifiesOutputFmt(cmd *cobra.Command) bool {
|
||||
return cmdutil.GetFlagString(cmd, "output") != ""
|
||||
}
|
||||
|
||||
// outputOptsForMappingFromOpenAPI looks for the output format metatadata in the
|
||||
// openapi schema and returns the output options for the mapping if found.
|
||||
func outputOptsForMappingFromOpenAPI(f cmdutil.Factory, openAPIcacheDir string, mapping *meta.RESTMapping) (*printers.OutputOptions, bool) {
|
||||
|
||||
// user has not specified any output format, check if OpenAPI has
|
||||
// default specification to print this resource type
|
||||
api, err := f.OpenAPISchema(openAPIcacheDir)
|
||||
if err != nil {
|
||||
// Error getting schema
|
||||
return nil, false
|
||||
}
|
||||
// Found openapi metadata for this resource
|
||||
kind, found := api.LookupResource(mapping.GroupVersionKind)
|
||||
if !found {
|
||||
// Kind not found, return empty columns
|
||||
return nil, false
|
||||
}
|
||||
|
||||
columns, found := openapi.GetPrintColumns(kind.Extensions)
|
||||
if !found {
|
||||
// Extension not found, return empty columns
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return outputOptsFromStr(columns)
|
||||
}
|
||||
|
||||
// outputOptsFromStr parses the print-column metadata and generates printer.OutputOptions object.
|
||||
func outputOptsFromStr(columnStr string) (*printers.OutputOptions, bool) {
|
||||
if columnStr == "" {
|
||||
return nil, false
|
||||
}
|
||||
parts := strings.SplitN(columnStr, "=", 2)
|
||||
if len(parts) < 2 {
|
||||
return nil, false
|
||||
}
|
||||
return &printers.OutputOptions{
|
||||
FmtType: parts[0],
|
||||
FmtArg: parts[1],
|
||||
AllowMissingKeys: true,
|
||||
}, true
|
||||
}
|
||||
|
@ -26,6 +26,8 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/go-openapi/spec"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@ -42,6 +44,7 @@ import (
|
||||
"k8s.io/kubernetes/pkg/api/testapi"
|
||||
apitesting "k8s.io/kubernetes/pkg/api/testing"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi"
|
||||
)
|
||||
|
||||
func testData() (*api.PodList, *api.ServiceList, *api.ReplicationControllerList) {
|
||||
@ -185,6 +188,56 @@ func TestGetSchemaObject(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetObjectsWithOpenAPIOutputFormatPresent(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
f, tf, codec, _ := cmdtesting.NewAPIFactory()
|
||||
tf.Printer = &testPrinter{}
|
||||
// overide the openAPISchema function to return custom output
|
||||
// for Pod type.
|
||||
tf.OpenAPISchemaFunc = testOpenAPISchemaData
|
||||
tf.UnstructuredClient = &fake.RESTClient{
|
||||
APIRegistry: api.Registry,
|
||||
NegotiatedSerializer: unstructuredSerializer,
|
||||
Resp: &http.Response{StatusCode: 200, Header: defaultHeader(), Body: objBody(codec, &pods.Items[0])},
|
||||
}
|
||||
tf.Namespace = "test"
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
errBuf := bytes.NewBuffer([]byte{})
|
||||
|
||||
cmd := NewCmdGet(f, buf, errBuf)
|
||||
cmd.SetOutput(buf)
|
||||
cmd.Flags().Set(useOpenAPIPrintColumnFlagLabel, "true")
|
||||
cmd.Run(cmd, []string{"pods", "foo"})
|
||||
|
||||
expected := []runtime.Object{&pods.Items[0]}
|
||||
verifyObjects(t, expected, tf.Printer.(*testPrinter).Objects)
|
||||
|
||||
if len(buf.String()) == 0 {
|
||||
t.Errorf("unexpected empty output")
|
||||
}
|
||||
}
|
||||
|
||||
func testOpenAPISchemaData() (*openapi.Resources, error) {
|
||||
return &openapi.Resources{
|
||||
GroupVersionKindToName: map[schema.GroupVersionKind]string{
|
||||
{
|
||||
Version: "v1",
|
||||
Kind: "Pod",
|
||||
}: "io.k8s.kubernetes.pkg.api.v1.Pod",
|
||||
},
|
||||
NameToDefinition: map[string]openapi.Kind{
|
||||
"io.k8s.kubernetes.pkg.api.v1.Pod": {
|
||||
Name: "io.k8s.kubernetes.pkg.api.v1.Pod",
|
||||
IsResource: false,
|
||||
Extensions: spec.Extensions{
|
||||
"x-kubernetes-print-columns": "custom-columns=NAME:.metadata.name,RSRC:.metadata.resourceVersion",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func TestGetObjects(t *testing.T) {
|
||||
pods, _, _ := testData()
|
||||
|
||||
|
@ -23,7 +23,7 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/emicklei/go-restful-swagger12"
|
||||
swagger "github.com/emicklei/go-restful-swagger12"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
@ -230,6 +230,7 @@ type TestFactory struct {
|
||||
|
||||
ClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
UnstructuredClientForMappingFunc func(mapping *meta.RESTMapping) (resource.RESTClient, error)
|
||||
OpenAPISchemaFunc func() (*openapi.Resources, error)
|
||||
}
|
||||
|
||||
type FakeFactory struct {
|
||||
@ -336,7 +337,7 @@ func (f *FakeFactory) Describer(*meta.RESTMapping) (printers.Describer, error) {
|
||||
return f.tf.Describer, f.tf.Err
|
||||
}
|
||||
|
||||
func (f *FakeFactory) PrinterForCommand(cmd *cobra.Command, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||
func (f *FakeFactory) PrinterForCommand(cmd *cobra.Command, outputOpts *printers.OutputOptions, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||
return f.tf.Printer, f.tf.Err
|
||||
}
|
||||
|
||||
@ -460,7 +461,7 @@ func (f *FakeFactory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, ob
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *FakeFactory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
|
||||
func (f *FakeFactory) PrinterForMapping(cmd *cobra.Command, outputOpts *printers.OutputOptions, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
|
||||
return f.tf.Printer, f.tf.Err
|
||||
}
|
||||
|
||||
@ -617,7 +618,7 @@ func (f *fakeAPIFactory) UnstructuredClientForMapping(m *meta.RESTMapping) (reso
|
||||
return f.tf.UnstructuredClient, f.tf.Err
|
||||
}
|
||||
|
||||
func (f *fakeAPIFactory) PrinterForCommand(cmd *cobra.Command, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||
func (f *fakeAPIFactory) PrinterForCommand(cmd *cobra.Command, outputOpts *printers.OutputOptions, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||
return f.tf.Printer, f.tf.Err
|
||||
}
|
||||
|
||||
@ -691,14 +692,14 @@ func (f *fakeAPIFactory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper,
|
||||
return err
|
||||
}
|
||||
|
||||
printer, err := f.PrinterForMapping(cmd, mapping, false)
|
||||
printer, err := f.PrinterForMapping(cmd, nil, mapping, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printer.PrintObj(obj, out)
|
||||
}
|
||||
|
||||
func (f *fakeAPIFactory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
|
||||
func (f *fakeAPIFactory) PrinterForMapping(cmd *cobra.Command, outputOpts *printers.OutputOptions, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
|
||||
return f.tf.Printer, f.tf.Err
|
||||
}
|
||||
|
||||
@ -712,6 +713,17 @@ func (f *fakeAPIFactory) SuggestedPodTemplateResources() []schema.GroupResource
|
||||
return []schema.GroupResource{}
|
||||
}
|
||||
|
||||
func (f *fakeAPIFactory) SwaggerSchema(schema.GroupVersionKind) (*swagger.ApiDeclaration, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (f *fakeAPIFactory) OpenAPISchema(cacheDir string) (*openapi.Resources, error) {
|
||||
if f.tf.OpenAPISchemaFunc != nil {
|
||||
return f.tf.OpenAPISchemaFunc()
|
||||
}
|
||||
return &openapi.Resources{}, nil
|
||||
}
|
||||
|
||||
func NewAPIFactory() (cmdutil.Factory, *TestFactory, runtime.Codec, runtime.NegotiatedSerializer) {
|
||||
t := &TestFactory{
|
||||
Validator: validation.NullSchema{},
|
||||
|
@ -233,10 +233,12 @@ type BuilderFactory interface {
|
||||
// are declared on the command (see AddPrinterFlags). Returns a printer, or an error if a printer
|
||||
// could not be found.
|
||||
// TODO: Break the dependency on cmd here.
|
||||
PrinterForCommand(cmd *cobra.Command, options printers.PrintOptions) (printers.ResourcePrinter, error)
|
||||
PrinterForCommand(cmd *cobra.Command, outputOpts *printers.OutputOptions, options printers.PrintOptions) (printers.ResourcePrinter, error)
|
||||
// PrinterForMapping returns a printer suitable for displaying the provided resource type.
|
||||
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
||||
PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error)
|
||||
// Returns a printer, true if the printer is generic (is not internal), or
|
||||
// an error if a printer could not be found.
|
||||
PrinterForMapping(cmd *cobra.Command, outputOpts *printers.OutputOptions, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error)
|
||||
// PrintObject prints an api object given command line flags to modify the output format
|
||||
PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, obj runtime.Object, out io.Writer) error
|
||||
// One stop shopping for a Builder
|
||||
|
@ -48,7 +48,7 @@ func NewBuilderFactory(clientAccessFactory ClientAccessFactory, objectMappingFac
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *ring2Factory) PrinterForCommand(cmd *cobra.Command, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||
func (f *ring2Factory) PrinterForCommand(cmd *cobra.Command, outputOpts *printers.OutputOptions, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||
mapper, typer, err := f.objectMappingFactory.UnstructuredObject()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -56,10 +56,10 @@ func (f *ring2Factory) PrinterForCommand(cmd *cobra.Command, options printers.Pr
|
||||
// TODO: used by the custom column implementation and the name implementation, break this dependency
|
||||
decoders := []runtime.Decoder{f.clientAccessFactory.Decoder(true), unstructured.UnstructuredJSONScheme}
|
||||
encoder := f.clientAccessFactory.JSONEncoder()
|
||||
return PrinterForCommand(cmd, mapper, typer, encoder, decoders, options)
|
||||
return PrinterForCommand(cmd, outputOpts, mapper, typer, encoder, decoders, options)
|
||||
}
|
||||
|
||||
func (f *ring2Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
|
||||
func (f *ring2Factory) PrinterForMapping(cmd *cobra.Command, outputOpts *printers.OutputOptions, mapping *meta.RESTMapping, withNamespace bool) (printers.ResourcePrinter, error) {
|
||||
// Some callers do not have "label-columns" so we can't use the GetFlagStringSlice() helper
|
||||
columnLabel, err := cmd.Flags().GetStringSlice("label-columns")
|
||||
if err != nil {
|
||||
@ -76,7 +76,7 @@ func (f *ring2Factory) PrinterForMapping(cmd *cobra.Command, mapping *meta.RESTM
|
||||
ColumnLabels: columnLabel,
|
||||
}
|
||||
|
||||
printer, err := f.PrinterForCommand(cmd, options)
|
||||
printer, err := f.PrinterForCommand(cmd, outputOpts, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -132,7 +132,7 @@ func (f *ring2Factory) PrintObject(cmd *cobra.Command, mapper meta.RESTMapper, o
|
||||
return err
|
||||
}
|
||||
|
||||
printer, err := f.PrinterForMapping(cmd, mapping, false)
|
||||
printer, err := f.PrinterForMapping(cmd, nil, mapping, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/emicklei/go-restful-swagger12"
|
||||
swagger "github.com/emicklei/go-restful-swagger12"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -417,6 +417,10 @@ func AddOpenAPIFlags(cmd *cobra.Command) {
|
||||
cmd.MarkFlagFilename("schema-cache-dir")
|
||||
}
|
||||
|
||||
func GetOpenAPICacheDir(cmd *cobra.Command) string {
|
||||
return GetFlagString(cmd, "schema-cache-dir")
|
||||
}
|
||||
|
||||
func AddFilenameOptionFlags(cmd *cobra.Command, options *resource.FilenameOptions, usage string) {
|
||||
kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, "Filename, directory, or URL to files "+usage)
|
||||
cmd.Flags().BoolVarP(&options.Recursive, "recursive", "R", options.Recursive, "Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory.")
|
||||
|
@ -12,6 +12,7 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"extensions.go",
|
||||
"openapi.go",
|
||||
"openapi_cache.go",
|
||||
"openapi_getter.go",
|
||||
|
26
pkg/kubectl/cmd/util/openapi/extensions.go
Normal file
26
pkg/kubectl/cmd/util/openapi/extensions.go
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
Copyright 2017 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package openapi
|
||||
|
||||
import "github.com/go-openapi/spec"
|
||||
|
||||
const PrintColumnsKey = "x-kubernetes-print-columns"
|
||||
|
||||
// GetPrintColumns looks for the open API extension for the display columns.
|
||||
func GetPrintColumns(extensions spec.Extensions) (string, bool) {
|
||||
return extensions.GetString(PrintColumnsKey)
|
||||
}
|
@ -194,7 +194,7 @@ func (o *Resources) parseDefinition(name string, s spec.Schema) Kind {
|
||||
Fields: map[string]Type{},
|
||||
}
|
||||
if err != nil {
|
||||
glog.Warning(err)
|
||||
glog.V(2).Info(err)
|
||||
}
|
||||
|
||||
// Definition represents a primitive type - e.g.
|
||||
|
@ -105,38 +105,18 @@ func ValidateOutputArgs(cmd *cobra.Command) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// PrinterForCommand returns the default printer for this command.
|
||||
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
||||
func PrinterForCommand(cmd *cobra.Command, mapper meta.RESTMapper, typer runtime.ObjectTyper, encoder runtime.Encoder, decoders []runtime.Decoder, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||
outputFormat := GetFlagString(cmd, "output")
|
||||
// PrinterForCommand returns the printer for the outputOptions (if given) or
|
||||
// returns the default printer for the command. Requires that printer flags have
|
||||
// been added to cmd (see AddPrinterFlags).
|
||||
// TODO: remove the dependency on cmd object
|
||||
func PrinterForCommand(cmd *cobra.Command, outputOpts *printers.OutputOptions, mapper meta.RESTMapper, typer runtime.ObjectTyper, encoder runtime.Encoder, decoders []runtime.Decoder, options printers.PrintOptions) (printers.ResourcePrinter, error) {
|
||||
|
||||
// templates are logically optional for specifying a format.
|
||||
// TODO once https://github.com/kubernetes/kubernetes/issues/12668 is fixed, this should fall back to GetFlagString
|
||||
templateFile, _ := cmd.Flags().GetString("template")
|
||||
if len(outputFormat) == 0 && len(templateFile) != 0 {
|
||||
outputFormat = "template"
|
||||
if outputOpts == nil {
|
||||
outputOpts = extractOutputOptions(cmd)
|
||||
}
|
||||
|
||||
templateFormat := []string{
|
||||
"go-template=", "go-template-file=", "jsonpath=", "jsonpath-file=", "custom-columns=", "custom-columns-file=",
|
||||
}
|
||||
for _, format := range templateFormat {
|
||||
if strings.HasPrefix(outputFormat, format) {
|
||||
templateFile = outputFormat[len(format):]
|
||||
outputFormat = format[:len(format)-1]
|
||||
}
|
||||
}
|
||||
|
||||
// this function may be invoked by a command that did not call AddPrinterFlags first, so we need
|
||||
// to be safe about how we access the allow-missing-template-keys flag
|
||||
allowMissingTemplateKeys := false
|
||||
if cmd.Flags().Lookup("allow-missing-template-keys") != nil {
|
||||
allowMissingTemplateKeys = GetFlagBool(cmd, "allow-missing-template-keys")
|
||||
}
|
||||
printer, err := printers.GetStandardPrinter(
|
||||
outputFormat, templateFile, GetFlagBool(cmd, "no-headers"), allowMissingTemplateKeys,
|
||||
mapper, typer, encoder, decoders, options,
|
||||
)
|
||||
printer, err := printers.GetStandardPrinter(outputOpts,
|
||||
GetFlagBool(cmd, "no-headers"), mapper, typer, encoder, decoders, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -149,12 +129,12 @@ func PrinterForCommand(cmd *cobra.Command, mapper meta.RESTMapper, typer runtime
|
||||
// object passed is non-generic, it attempts to print the object using a HumanReadablePrinter.
|
||||
// Requires that printer flags have been added to cmd (see AddPrinterFlags).
|
||||
func PrintResourceInfoForCommand(cmd *cobra.Command, info *resource.Info, f Factory, out io.Writer) error {
|
||||
printer, err := f.PrinterForCommand(cmd, printers.PrintOptions{})
|
||||
printer, err := f.PrinterForCommand(cmd, nil, printers.PrintOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !printer.IsGeneric() {
|
||||
printer, err = f.PrinterForMapping(cmd, nil, false)
|
||||
printer, err = f.PrinterForMapping(cmd, nil, nil, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -162,6 +142,50 @@ func PrintResourceInfoForCommand(cmd *cobra.Command, info *resource.Info, f Fact
|
||||
return printer.PrintObj(info.Object, out)
|
||||
}
|
||||
|
||||
// extractOutputOptions parses printer specific commandline args and returns
|
||||
// printers.OutputsOptions object.
|
||||
func extractOutputOptions(cmd *cobra.Command) *printers.OutputOptions {
|
||||
flags := cmd.Flags()
|
||||
|
||||
var outputFormat string
|
||||
if flags.Lookup("output") != nil {
|
||||
outputFormat = GetFlagString(cmd, "output")
|
||||
}
|
||||
|
||||
// templates are logically optional for specifying a format.
|
||||
// TODO once https://github.com/kubernetes/kubernetes/issues/12668 is fixed, this should fall back to GetFlagString
|
||||
var templateFile string
|
||||
if flags.Lookup("template") != nil {
|
||||
templateFile = GetFlagString(cmd, "template")
|
||||
}
|
||||
if len(outputFormat) == 0 && len(templateFile) != 0 {
|
||||
outputFormat = "template"
|
||||
}
|
||||
|
||||
templateFormats := []string{
|
||||
"go-template=", "go-template-file=", "jsonpath=", "jsonpath-file=", "custom-columns=", "custom-columns-file=",
|
||||
}
|
||||
for _, format := range templateFormats {
|
||||
if strings.HasPrefix(outputFormat, format) {
|
||||
templateFile = outputFormat[len(format):]
|
||||
outputFormat = format[:len(format)-1]
|
||||
}
|
||||
}
|
||||
|
||||
// this function may be invoked by a command that did not call AddPrinterFlags first, so we need
|
||||
// to be safe about how we access the allow-missing-template-keys flag
|
||||
allowMissingTemplateKeys := false
|
||||
if flags.Lookup("allow-missing-template-keys") != nil {
|
||||
allowMissingTemplateKeys = GetFlagBool(cmd, "allow-missing-template-keys")
|
||||
}
|
||||
|
||||
return &printers.OutputOptions{
|
||||
FmtType: outputFormat,
|
||||
FmtArg: templateFile,
|
||||
AllowMissingKeys: allowMissingTemplateKeys,
|
||||
}
|
||||
}
|
||||
|
||||
func maybeWrapSortingPrinter(cmd *cobra.Command, printer printers.ResourcePrinter) printers.ResourcePrinter {
|
||||
sorting, err := cmd.Flags().GetString("sort-by")
|
||||
if err != nil {
|
||||
|
@ -153,6 +153,9 @@ type CustomColumnsPrinter struct {
|
||||
Columns []Column
|
||||
Decoder runtime.Decoder
|
||||
NoHeaders bool
|
||||
// lastType records type of resource printed last so that we don't repeat
|
||||
// header while printing same type of resources.
|
||||
lastType reflect.Type
|
||||
}
|
||||
|
||||
func (s *CustomColumnsPrinter) AfterPrint(w io.Writer, res string) error {
|
||||
@ -162,12 +165,14 @@ func (s *CustomColumnsPrinter) AfterPrint(w io.Writer, res string) error {
|
||||
func (s *CustomColumnsPrinter) PrintObj(obj runtime.Object, out io.Writer) error {
|
||||
w := tabwriter.NewWriter(out, columnwidth, tabwidth, padding, padding_character, flags)
|
||||
|
||||
if !s.NoHeaders {
|
||||
t := reflect.TypeOf(obj)
|
||||
if !s.NoHeaders && t != s.lastType {
|
||||
headers := make([]string, len(s.Columns))
|
||||
for ix := range s.Columns {
|
||||
headers[ix] = s.Columns[ix].Header
|
||||
}
|
||||
fmt.Fprintln(w, strings.Join(headers, "\t"))
|
||||
s.lastType = t
|
||||
}
|
||||
parsers := make([]*jsonpath.JSONPath, len(s.Columns))
|
||||
for ix := range s.Columns {
|
||||
|
@ -100,3 +100,13 @@ type ErrNoDescriber struct {
|
||||
func (e ErrNoDescriber) Error() string {
|
||||
return fmt.Sprintf("no describer has been defined for %v", e.Types)
|
||||
}
|
||||
|
||||
// OutputOptions represents resource output options which is used to generate a resource printer.
|
||||
type OutputOptions struct {
|
||||
// supported Format types can be found in pkg/printers/printers.go
|
||||
FmtType string
|
||||
FmtArg string
|
||||
|
||||
// indicates if it is OK to ignore missing keys for rendering an output template.
|
||||
AllowMissingKeys bool
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ func TestPrintDefault(t *testing.T) {
|
||||
}
|
||||
|
||||
for _, test := range printerTests {
|
||||
printer, err := printers.GetStandardPrinter(test.Format, "", false, false, nil, nil, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||
printer, err := printers.GetStandardPrinter(&printers.OutputOptions{AllowMissingKeys: false}, false, nil, nil, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("in %s, unexpected error: %#v", test.Name, err)
|
||||
}
|
||||
@ -131,25 +131,24 @@ func TestPrinter(t *testing.T) {
|
||||
|
||||
printerTests := []struct {
|
||||
Name string
|
||||
Format string
|
||||
FormatArgument string
|
||||
OutputOpts *printers.OutputOptions
|
||||
Input runtime.Object
|
||||
OutputVersions []schema.GroupVersion
|
||||
Expect string
|
||||
}{
|
||||
{"test json", "json", "", simpleTest, nil, "{\n \"Data\": \"foo\"\n}\n"},
|
||||
{"test yaml", "yaml", "", simpleTest, nil, "Data: foo\n"},
|
||||
{"test template", "template", "{{if .id}}{{.id}}{{end}}{{if .metadata.name}}{{.metadata.name}}{{end}}",
|
||||
{"test json", &printers.OutputOptions{FmtType: "json", AllowMissingKeys: true}, simpleTest, nil, "{\n \"Data\": \"foo\"\n}\n"},
|
||||
{"test yaml", &printers.OutputOptions{FmtType: "yaml", AllowMissingKeys: true}, simpleTest, nil, "Data: foo\n"},
|
||||
{"test template", &printers.OutputOptions{FmtType: "template", FmtArg: "{{if .id}}{{.id}}{{end}}{{if .metadata.name}}{{.metadata.name}}{{end}}", AllowMissingKeys: true},
|
||||
podTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "foo"},
|
||||
{"test jsonpath", "jsonpath", "{.metadata.name}", podTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "foo"},
|
||||
{"test jsonpath list", "jsonpath", "{.items[*].metadata.name}", podListTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "foo bar"},
|
||||
{"test jsonpath empty list", "jsonpath", "{.items[*].metadata.name}", emptyListTest, []schema.GroupVersion{v1.SchemeGroupVersion}, ""},
|
||||
{"test name", "name", "", podTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "pods/foo\n"},
|
||||
{"emits versioned objects", "template", "{{.kind}}", testapi, []schema.GroupVersion{v1.SchemeGroupVersion}, "Pod"},
|
||||
{"test jsonpath", &printers.OutputOptions{FmtType: "jsonpath", FmtArg: "{.metadata.name}", AllowMissingKeys: true}, podTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "foo"},
|
||||
{"test jsonpath list", &printers.OutputOptions{FmtType: "jsonpath", FmtArg: "{.items[*].metadata.name}", AllowMissingKeys: true}, podListTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "foo bar"},
|
||||
{"test jsonpath empty list", &printers.OutputOptions{FmtType: "jsonpath", FmtArg: "{.items[*].metadata.name}", AllowMissingKeys: true}, emptyListTest, []schema.GroupVersion{v1.SchemeGroupVersion}, ""},
|
||||
{"test name", &printers.OutputOptions{FmtType: "name", AllowMissingKeys: true}, podTest, []schema.GroupVersion{v1.SchemeGroupVersion}, "pods/foo\n"},
|
||||
{"emits versioned objects", &printers.OutputOptions{FmtType: "template", FmtArg: "{{.kind}}", AllowMissingKeys: true}, testapi, []schema.GroupVersion{v1.SchemeGroupVersion}, "Pod"},
|
||||
}
|
||||
for _, test := range printerTests {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
printer, err := printers.GetStandardPrinter(test.Format, test.FormatArgument, false, true, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||
printer, err := printers.GetStandardPrinter(test.OutputOpts, false, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("in %s, unexpected error: %#v", test.Name, err)
|
||||
}
|
||||
@ -168,19 +167,18 @@ func TestPrinter(t *testing.T) {
|
||||
|
||||
func TestBadPrinter(t *testing.T) {
|
||||
badPrinterTests := []struct {
|
||||
Name string
|
||||
Format string
|
||||
FormatArgument string
|
||||
Error error
|
||||
Name string
|
||||
OutputOpts *printers.OutputOptions
|
||||
Error error
|
||||
}{
|
||||
{"empty template", "template", "", fmt.Errorf("template format specified but no template given")},
|
||||
{"bad template", "template", "{{ .Name", fmt.Errorf("error parsing template {{ .Name, template: output:1: unclosed action\n")},
|
||||
{"bad templatefile", "templatefile", "", fmt.Errorf("templatefile format specified but no template file given")},
|
||||
{"bad jsonpath", "jsonpath", "{.Name", fmt.Errorf("error parsing jsonpath {.Name, unclosed action\n")},
|
||||
{"unknown format", "anUnknownFormat", "", fmt.Errorf("output format \"anUnknownFormat\" not recognized")},
|
||||
{"empty template", &printers.OutputOptions{FmtType: "template", AllowMissingKeys: false}, fmt.Errorf("template format specified but no template given")},
|
||||
{"bad template", &printers.OutputOptions{FmtType: "template", FmtArg: "{{ .Name", AllowMissingKeys: false}, fmt.Errorf("error parsing template {{ .Name, template: output:1: unclosed action\n")},
|
||||
{"bad templatefile", &printers.OutputOptions{FmtType: "templatefile", AllowMissingKeys: false}, fmt.Errorf("templatefile format specified but no template file given")},
|
||||
{"bad jsonpath", &printers.OutputOptions{FmtType: "jsonpath", FmtArg: "{.Name", AllowMissingKeys: false}, fmt.Errorf("error parsing jsonpath {.Name, unclosed action\n")},
|
||||
{"unknown format", &printers.OutputOptions{FmtType: "anUnknownFormat", FmtArg: "", AllowMissingKeys: false}, fmt.Errorf("output format \"anUnknownFormat\" not recognized")},
|
||||
}
|
||||
for _, test := range badPrinterTests {
|
||||
_, err := printers.GetStandardPrinter(test.Format, test.FormatArgument, false, false, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||
_, err := printers.GetStandardPrinter(test.OutputOpts, false, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||
if err == nil || err.Error() != test.Error.Error() {
|
||||
t.Errorf("in %s, expect %s, got %s", test.Name, test.Error, err)
|
||||
}
|
||||
@ -373,7 +371,8 @@ func TestNamePrinter(t *testing.T) {
|
||||
},
|
||||
"pods/foo\npods/bar\n"},
|
||||
}
|
||||
printer, _ := printers.GetStandardPrinter("name", "", false, false, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||
outputOpts := &printers.OutputOptions{FmtType: "name", AllowMissingKeys: false}
|
||||
printer, _ := printers.GetStandardPrinter(outputOpts, false, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||
for name, item := range tests {
|
||||
buff := &bytes.Buffer{}
|
||||
err := printer.PrintObj(item.obj, buff)
|
||||
@ -2309,22 +2308,20 @@ func TestPrintPodDisruptionBudget(t *testing.T) {
|
||||
|
||||
func TestAllowMissingKeys(t *testing.T) {
|
||||
tests := []struct {
|
||||
Name string
|
||||
AllowMissingTemplateKeys bool
|
||||
Format string
|
||||
Template string
|
||||
Input runtime.Object
|
||||
Expect string
|
||||
Error string
|
||||
Name string
|
||||
OutputOpts *printers.OutputOptions
|
||||
Input runtime.Object
|
||||
Expect string
|
||||
Error string
|
||||
}{
|
||||
{"test template, allow missing keys", true, "template", "{{.blarg}}", &api.Pod{}, "<no value>", ""},
|
||||
{"test template, strict", false, "template", "{{.blarg}}", &api.Pod{}, "", `error executing template "{{.blarg}}": template: output:1:2: executing "output" at <.blarg>: map has no entry for key "blarg"`},
|
||||
{"test jsonpath, allow missing keys", true, "jsonpath", "{.blarg}", &api.Pod{}, "", ""},
|
||||
{"test jsonpath, strict", false, "jsonpath", "{.blarg}", &api.Pod{}, "", "error executing jsonpath \"{.blarg}\": blarg is not found\n"},
|
||||
{"test template, allow missing keys", &printers.OutputOptions{FmtType: "template", FmtArg: "{{.blarg}}", AllowMissingKeys: true}, &api.Pod{}, "<no value>", ""},
|
||||
{"test template, strict", &printers.OutputOptions{FmtType: "template", FmtArg: "{{.blarg}}", AllowMissingKeys: false}, &api.Pod{}, "", `error executing template "{{.blarg}}": template: output:1:2: executing "output" at <.blarg>: map has no entry for key "blarg"`},
|
||||
{"test jsonpath, allow missing keys", &printers.OutputOptions{FmtType: "jsonpath", FmtArg: "{.blarg}", AllowMissingKeys: true}, &api.Pod{}, "", ""},
|
||||
{"test jsonpath, strict", &printers.OutputOptions{FmtType: "jsonpath", FmtArg: "{.blarg}", AllowMissingKeys: false}, &api.Pod{}, "", "error executing jsonpath \"{.blarg}\": blarg is not found\n"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
printer, err := printers.GetStandardPrinter(test.Format, test.Template, false, test.AllowMissingTemplateKeys, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||
printer, err := printers.GetStandardPrinter(test.OutputOpts, false, api.Registry.RESTMapper(api.Registry.EnabledVersions()...), api.Scheme, api.Codecs.LegacyCodec(api.Registry.EnabledVersions()...), []runtime.Decoder{api.Codecs.UniversalDecoder(), unstructured.UnstructuredJSONScheme}, printers.PrintOptions{})
|
||||
if err != nil {
|
||||
t.Errorf("in %s, unexpected error: %#v", test.Name, err)
|
||||
}
|
||||
|
@ -29,7 +29,13 @@ import (
|
||||
// a printer or an error. The printer is agnostic to schema versions, so you must
|
||||
// send arguments to PrintObj in the version you wish them to be shown using a
|
||||
// VersionedPrinter (typically when generic is true).
|
||||
func GetStandardPrinter(format, formatArgument string, noHeaders, allowMissingTemplateKeys bool, mapper meta.RESTMapper, typer runtime.ObjectTyper, encoder runtime.Encoder, decoders []runtime.Decoder, options PrintOptions) (ResourcePrinter, error) {
|
||||
func GetStandardPrinter(outputOpts *OutputOptions, noHeaders bool, mapper meta.RESTMapper, typer runtime.ObjectTyper, encoder runtime.Encoder, decoders []runtime.Decoder, options PrintOptions) (ResourcePrinter, error) {
|
||||
if outputOpts == nil {
|
||||
return nil, fmt.Errorf("no output options specified")
|
||||
}
|
||||
|
||||
format, formatArgument, allowMissingTemplateKeys := outputOpts.FmtType, outputOpts.FmtArg, outputOpts.AllowMissingKeys
|
||||
|
||||
var printer ResourcePrinter
|
||||
switch format {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user