From 2aa4abb73b305c7c868107831bc007aa1c952f86 Mon Sep 17 00:00:00 2001 From: Clayton Coleman Date: Sun, 19 Feb 2017 17:56:11 -0500 Subject: [PATCH] Refactor commands to use new factory method --- cmd/kubeadm/app/cmd/token.go | 4 +- pkg/kubectl/cmd/annotate.go | 3 +- pkg/kubectl/cmd/clusterinfo_dump.go | 7 +-- pkg/kubectl/cmd/cmd_test.go | 39 ++++++++++----- pkg/kubectl/cmd/config/config.go | 2 +- pkg/kubectl/cmd/config/get_contexts.go | 5 +- pkg/kubectl/cmd/config/view.go | 18 ++++--- pkg/kubectl/cmd/convert.go | 8 ++-- pkg/kubectl/cmd/delete.go | 3 +- pkg/kubectl/cmd/describe.go | 12 +++-- pkg/kubectl/cmd/edit.go | 13 ++--- pkg/kubectl/cmd/expose_test.go | 4 +- pkg/kubectl/cmd/get.go | 9 ++-- pkg/kubectl/cmd/get_test.go | 55 ++++++++++++---------- pkg/kubectl/cmd/label.go | 3 +- pkg/kubectl/cmd/patch.go | 3 +- pkg/kubectl/cmd/set/set_image_test.go | 10 ++-- pkg/kubectl/cmd/testing/fake.go | 4 +- pkg/kubectl/history.go | 21 ++++++++- pkg/kubectl/kubectl.go | 13 ----- pkg/kubectl/metricsutil/metrics_printer.go | 6 +-- pkg/kubectl/resource_filter.go | 7 +-- pkg/kubectl/rollback.go | 5 +- pkg/kubectl/sorting_printer.go | 5 +- 24 files changed, 153 insertions(+), 106 deletions(-) diff --git a/cmd/kubeadm/app/cmd/token.go b/cmd/kubeadm/app/cmd/token.go index 848a3be7b4..b4360dfb65 100644 --- a/cmd/kubeadm/app/cmd/token.go +++ b/cmd/kubeadm/app/cmd/token.go @@ -37,7 +37,7 @@ import ( kubeconfigutil "k8s.io/kubernetes/cmd/kubeadm/app/util/kubeconfig" tokenutil "k8s.io/kubernetes/cmd/kubeadm/app/util/token" bootstrapapi "k8s.io/kubernetes/pkg/bootstrap/api" - "k8s.io/kubernetes/pkg/kubectl" + "k8s.io/kubernetes/pkg/printers" ) func NewCmdToken(out io.Writer, errW io.Writer) *cobra.Command { @@ -207,7 +207,7 @@ func RunListTokens(out io.Writer, errW io.Writer, cmd *cobra.Command) error { if err != nil { return fmt.Errorf("error parsing expiration time [%v]", err) } - expires = kubectl.ShortHumanDuration(expireTime.Sub(time.Now())) + expires = printers.ShortHumanDuration(expireTime.Sub(time.Now())) } fmt.Fprintf(w, "%s\t%s\t%s\n", tokenId, tokenutil.BearerToken(td), expires) } diff --git a/pkg/kubectl/cmd/annotate.go b/pkg/kubectl/cmd/annotate.go index dd65ac0761..f61ff45ac2 100644 --- a/pkg/kubectl/cmd/annotate.go +++ b/pkg/kubectl/cmd/annotate.go @@ -36,6 +36,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/util/i18n" ) @@ -101,7 +102,7 @@ func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command { // retrieve a list of handled resources from printer as valid args validArgs, argAliases := []string{}, []string{} - p, err := f.Printer(nil, kubectl.PrintOptions{ + p, err := f.Printer(nil, printers.PrintOptions{ ColumnLabels: []string{}, }) cmdutil.CheckErr(err) diff --git a/pkg/kubectl/cmd/clusterinfo_dump.go b/pkg/kubectl/cmd/clusterinfo_dump.go index 3c8133bd45..dabdac3e96 100644 --- a/pkg/kubectl/cmd/clusterinfo_dump.go +++ b/pkg/kubectl/cmd/clusterinfo_dump.go @@ -26,9 +26,9 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/util/i18n" ) @@ -93,10 +93,7 @@ func dumpClusterInfo(f cmdutil.Factory, cmd *cobra.Command, args []string, out i return err } - printer, _, err := kubectl.GetPrinter("json", "", false, true) - if err != nil { - return err - } + printer := &printers.JSONPrinter{} nodes, err := clientset.Core().Nodes().List(metav1.ListOptions{}) if err != nil { diff --git a/pkg/kubectl/cmd/cmd_test.go b/pkg/kubectl/cmd/cmd_test.go index 27ead0a2b0..9901f2b752 100644 --- a/pkg/kubectl/cmd/cmd_test.go +++ b/pkg/kubectl/cmd/cmd_test.go @@ -35,9 +35,10 @@ import ( "k8s.io/client-go/rest/fake" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/testapi" - "k8s.io/kubernetes/pkg/kubectl" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/printers" + printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" "k8s.io/kubernetes/pkg/util/strings" ) @@ -97,12 +98,12 @@ func (t *testPrinter) AfterPrint(output io.Writer, res string) error { type testDescriber struct { Name, Namespace string - Settings kubectl.DescriberSettings + Settings printers.DescriberSettings Output string Err error } -func (t *testDescriber) Describe(namespace, name string, describerSettings kubectl.DescriberSettings) (output string, err error) { +func (t *testDescriber) Describe(namespace, name string, describerSettings printers.DescriberSettings) (output string, err error) { t.Namespace, t.Name = namespace, name t.Settings = describerSettings return t.Output, t.Err @@ -146,10 +147,12 @@ func stringBody(body string) io.ReadCloser { func Example_printReplicationControllerWithNamespace() { f, tf, _, ns := cmdtesting.NewAPIFactory() - tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ + p := printers.NewHumanReadablePrinter(printers.PrintOptions{ WithNamespace: true, ColumnLabels: []string{}, }) + printersinternal.AddHandlers(p) + tf.Printer = p tf.Client = &fake.RESTClient{ APIRegistry: api.Registry, NegotiatedSerializer: ns, @@ -197,10 +200,12 @@ func Example_printReplicationControllerWithNamespace() { func Example_printMultiContainersReplicationControllerWithWide() { f, tf, _, ns := cmdtesting.NewAPIFactory() - tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ + p := printers.NewHumanReadablePrinter(printers.PrintOptions{ Wide: true, ColumnLabels: []string{}, }) + printersinternal.AddHandlers(p) + tf.Printer = p tf.Client = &fake.RESTClient{ APIRegistry: api.Registry, NegotiatedSerializer: ns, @@ -250,9 +255,11 @@ func Example_printMultiContainersReplicationControllerWithWide() { func Example_printReplicationController() { f, tf, _, ns := cmdtesting.NewAPIFactory() - tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ + p := printers.NewHumanReadablePrinter(printers.PrintOptions{ ColumnLabels: []string{}, }) + printersinternal.AddHandlers(p) + tf.Printer = p tf.Client = &fake.RESTClient{ APIRegistry: api.Registry, NegotiatedSerializer: ns, @@ -302,10 +309,12 @@ func Example_printReplicationController() { func Example_printPodWithWideFormat() { f, tf, _, ns := cmdtesting.NewAPIFactory() - tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ + p := printers.NewHumanReadablePrinter(printers.PrintOptions{ Wide: true, ColumnLabels: []string{}, }) + printersinternal.AddHandlers(p) + tf.Printer = p tf.Client = &fake.RESTClient{ APIRegistry: api.Registry, NegotiatedSerializer: ns, @@ -343,10 +352,12 @@ func Example_printPodWithWideFormat() { func Example_printPodWithShowLabels() { f, tf, _, ns := cmdtesting.NewAPIFactory() - tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ + p := printers.NewHumanReadablePrinter(printers.PrintOptions{ ShowLabels: true, ColumnLabels: []string{}, }) + printersinternal.AddHandlers(p) + tf.Printer = p tf.Client = &fake.RESTClient{ APIRegistry: api.Registry, NegotiatedSerializer: ns, @@ -479,9 +490,11 @@ func newAllPhasePodList() *api.PodList { func Example_printPodHideTerminated() { f, tf, _, ns := cmdtesting.NewAPIFactory() - tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ + p := printers.NewHumanReadablePrinter(printers.PrintOptions{ ColumnLabels: []string{}, }) + printersinternal.AddHandlers(p) + tf.Printer = p tf.Client = &fake.RESTClient{ APIRegistry: api.Registry, NegotiatedSerializer: ns, @@ -512,10 +525,12 @@ func Example_printPodHideTerminated() { func Example_printPodShowAll() { f, tf, _, ns := cmdtesting.NewAPIFactory() - tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ + p := printers.NewHumanReadablePrinter(printers.PrintOptions{ ShowAll: true, ColumnLabels: []string{}, }) + printersinternal.AddHandlers(p) + tf.Printer = p tf.Client = &fake.RESTClient{ APIRegistry: api.Registry, NegotiatedSerializer: ns, @@ -539,10 +554,12 @@ func Example_printPodShowAll() { func Example_printServiceWithNamespacesAndLabels() { f, tf, _, ns := cmdtesting.NewAPIFactory() - tf.Printer = kubectl.NewHumanReadablePrinter(kubectl.PrintOptions{ + p := printers.NewHumanReadablePrinter(printers.PrintOptions{ WithNamespace: true, ColumnLabels: []string{"l1"}, }) + printersinternal.AddHandlers(p) + tf.Printer = p tf.Client = &fake.RESTClient{ APIRegistry: api.Registry, NegotiatedSerializer: ns, diff --git a/pkg/kubectl/cmd/config/config.go b/pkg/kubectl/cmd/config/config.go index 639fb48123..fe49488444 100644 --- a/pkg/kubectl/cmd/config/config.go +++ b/pkg/kubectl/cmd/config/config.go @@ -52,7 +52,7 @@ func NewCmdConfig(pathOptions *clientcmd.PathOptions, out, errOut io.Writer) *co // file paths are common to all sub commands cmd.PersistentFlags().StringVar(&pathOptions.LoadingRules.ExplicitPath, pathOptions.ExplicitFileFlag, pathOptions.LoadingRules.ExplicitPath, "use a particular kubeconfig file") - cmd.AddCommand(NewCmdConfigView(out, pathOptions)) + cmd.AddCommand(NewCmdConfigView(out, errOut, pathOptions)) cmd.AddCommand(NewCmdConfigSetCluster(out, pathOptions)) cmd.AddCommand(NewCmdConfigSetAuthInfo(out, pathOptions)) cmd.AddCommand(NewCmdConfigSetContext(out, pathOptions)) diff --git a/pkg/kubectl/cmd/config/get_contexts.go b/pkg/kubectl/cmd/config/get_contexts.go index 0576a21a92..5c52014f69 100644 --- a/pkg/kubectl/cmd/config/get_contexts.go +++ b/pkg/kubectl/cmd/config/get_contexts.go @@ -23,13 +23,14 @@ import ( "text/tabwriter" "github.com/spf13/cobra" + utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/client-go/tools/clientcmd" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" - "k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/util/i18n" ) @@ -108,7 +109,7 @@ func (o GetContextsOptions) RunGetContexts() error { out, found := o.out.(*tabwriter.Writer) if !found { - out = kubectl.GetNewTabWriter(o.out) + out = printers.GetNewTabWriter(o.out) defer out.Flush() } diff --git a/pkg/kubectl/cmd/config/view.go b/pkg/kubectl/cmd/config/view.go index e3c9b28fb0..4c7cdb665d 100644 --- a/pkg/kubectl/cmd/config/view.go +++ b/pkg/kubectl/cmd/config/view.go @@ -23,13 +23,15 @@ import ( "github.com/spf13/cobra" + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apiserver/pkg/util/flag" "k8s.io/client-go/tools/clientcmd" clientcmdapi "k8s.io/client-go/tools/clientcmd/api" "k8s.io/client-go/tools/clientcmd/api/latest" - "k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/util/i18n" ) @@ -55,7 +57,7 @@ var ( kubectl config view -o jsonpath='{.users[?(@.name == "e2e")].user.password}'`) ) -func NewCmdConfigView(out io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra.Command { +func NewCmdConfigView(out, errOut io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra.Command { options := &ViewOptions{ConfigAccess: ConfigAccess} // Default to yaml defaultOutputFormat := "yaml" @@ -69,17 +71,19 @@ func NewCmdConfigView(out io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra options.Complete() outputFormat := cmdutil.GetFlagString(cmd, "output") if outputFormat == "wide" { - fmt.Printf("--output wide is not available in kubectl config view; reset to default output format (%s)\n\n", defaultOutputFormat) + fmt.Fprintf(errOut, "--output wide is not available in kubectl config view; reset to default output format (%s)\n\n", defaultOutputFormat) + // TODO: once printing is abstracted, this should be handled at flag declaration time cmd.Flags().Set("output", defaultOutputFormat) } if outputFormat == "" { - fmt.Printf("Reset to default output format (%s) as --output is empty\n", defaultOutputFormat) + fmt.Fprintf(errOut, "Reset to default output format (%s) as --output is empty\n", defaultOutputFormat) + // TODO: once printing is abstracted, this should be handled at flag declaration time cmd.Flags().Set("output", defaultOutputFormat) } - printer, _, err := cmdutil.PrinterForCommand(cmd) + printer, _, err := cmdutil.PrinterForCommand(cmd, meta.NewDefaultRESTMapper(nil, nil), latest.Scheme, []runtime.Decoder{latest.Codec}) cmdutil.CheckErr(err) - printer = kubectl.NewVersionedPrinter(printer, latest.Scheme, latest.ExternalVersion) + printer = printers.NewVersionedPrinter(printer, latest.Scheme, latest.ExternalVersion) cmdutil.CheckErr(options.Run(out, printer)) }, @@ -97,7 +101,7 @@ func NewCmdConfigView(out io.Writer, ConfigAccess clientcmd.ConfigAccess) *cobra return cmd } -func (o ViewOptions) Run(out io.Writer, printer kubectl.ResourcePrinter) error { +func (o ViewOptions) Run(out io.Writer, printer printers.ResourcePrinter) error { config, err := o.loadConfig() if err != nil { return err diff --git a/pkg/kubectl/cmd/convert.go b/pkg/kubectl/cmd/convert.go index 519f465a6c..a4697d7d0d 100644 --- a/pkg/kubectl/cmd/convert.go +++ b/pkg/kubectl/cmd/convert.go @@ -25,10 +25,10 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/kubernetes/pkg/api" - "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/resource" + "k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/util/i18n" "github.com/spf13/cobra" @@ -96,7 +96,7 @@ type ConvertOptions struct { encoder runtime.Encoder out io.Writer - printer kubectl.ResourcePrinter + printer printers.ResourcePrinter outputVersion schema.GroupVersion } @@ -160,9 +160,11 @@ func (o *ConvertOptions) Complete(f cmdutil.Factory, out io.Writer, cmd *cobra.C } else { outputFormat = "template" } + // TODO: once printing is abstracted, this should be handled at flag declaration time + cmd.Flags().Set("output", outputFormat) } o.encoder = f.JSONEncoder() - o.printer, _, err = kubectl.GetPrinter(outputFormat, templateFile, false, cmdutil.GetFlagBool(cmd, "allow-missing-template-keys")) + o.printer, _, err = f.PrinterForCommand(cmd) if err != nil { return err } diff --git a/pkg/kubectl/cmd/delete.go b/pkg/kubectl/cmd/delete.go index 7440edc834..1eada79b4b 100644 --- a/pkg/kubectl/cmd/delete.go +++ b/pkg/kubectl/cmd/delete.go @@ -32,6 +32,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/util/i18n" ) @@ -117,7 +118,7 @@ func NewCmdDelete(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { // retrieve a list of handled resources from printer as valid args validArgs, argAliases := []string{}, []string{} - p, err := f.Printer(nil, kubectl.PrintOptions{ + p, err := f.Printer(nil, printers.PrintOptions{ ColumnLabels: []string{}, }) cmdutil.CheckErr(err) diff --git a/pkg/kubectl/cmd/describe.go b/pkg/kubectl/cmd/describe.go index 37c5ce8988..c71bda26bb 100644 --- a/pkg/kubectl/cmd/describe.go +++ b/pkg/kubectl/cmd/describe.go @@ -33,6 +33,8 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/printers" + printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" "k8s.io/kubernetes/pkg/util/i18n" ) @@ -72,9 +74,11 @@ var ( func NewCmdDescribe(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command { options := &resource.FilenameOptions{} - describerSettings := &kubectl.DescriberSettings{} + describerSettings := &printers.DescriberSettings{} - validArgs := kubectl.DescribableResources() + // TODO: this should come from the factory, and may need to be loaded from the server, and so is probably + // going to have to be removed + validArgs := printersinternal.DescribableResources() argAliases := kubectl.ResourceAliases(validArgs) cmd := &cobra.Command{ @@ -98,7 +102,7 @@ func NewCmdDescribe(f cmdutil.Factory, out, cmdErr io.Writer) *cobra.Command { return cmd } -func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions, describerSettings *kubectl.DescriberSettings) error { +func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions, describerSettings *printers.DescriberSettings) error { selector := cmdutil.GetFlagString(cmd, "selector") allNamespaces := cmdutil.GetFlagBool(cmd, "all-namespaces") cmdNamespace, enforceNamespace, err := f.DefaultNamespace() @@ -172,7 +176,7 @@ func RunDescribe(f cmdutil.Factory, out, cmdErr io.Writer, cmd *cobra.Command, a return utilerrors.NewAggregate(allErrs) } -func DescribeMatchingResources(mapper meta.RESTMapper, typer runtime.ObjectTyper, f cmdutil.Factory, namespace, rsrc, prefix string, describerSettings *kubectl.DescriberSettings, out io.Writer, originalError error) error { +func DescribeMatchingResources(mapper meta.RESTMapper, typer runtime.ObjectTyper, f cmdutil.Factory, namespace, rsrc, prefix string, describerSettings *printers.DescriberSettings, out io.Writer, originalError error) error { mapper, typer, err := f.UnstructuredObject() if err != nil { return err diff --git a/pkg/kubectl/cmd/edit.go b/pkg/kubectl/cmd/edit.go index a6de724706..04555d2cdd 100644 --- a/pkg/kubectl/cmd/edit.go +++ b/pkg/kubectl/cmd/edit.go @@ -43,6 +43,7 @@ import ( cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/cmd/util/editor" "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/util/crlf" "k8s.io/kubernetes/pkg/util/i18n" @@ -64,9 +65,9 @@ var ( Editing is done with the API version used to fetch the resource. To edit using a specific API version, fully-qualify the resource, version, and group. - + The default format is YAML. To edit in JSON, specify "-o json". - + The flag --windows-line-endings can be used to force Windows line endings, otherwise the default for your operating system will be used. @@ -92,7 +93,7 @@ func NewCmdEdit(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { // retrieve a list of handled resources from printer as valid args validArgs, argAliases := []string{}, []string{} - p, err := f.Printer(nil, kubectl.PrintOptions{ + p, err := f.Printer(nil, printers.PrintOptions{ ColumnLabels: []string{}, }) cmdutil.CheckErr(err) @@ -343,14 +344,14 @@ func getPrinter(cmd *cobra.Command) (*editPrinterOptions, error) { switch format := cmdutil.GetFlagString(cmd, "output"); format { case "json": return &editPrinterOptions{ - printer: &kubectl.JSONPrinter{}, + printer: &printers.JSONPrinter{}, ext: ".json", addHeader: false, }, nil // If flag -o is not specified, use yaml as default case "yaml", "": return &editPrinterOptions{ - printer: &kubectl.YAMLPrinter{}, + printer: &printers.YAMLPrinter{}, ext: ".yaml", addHeader: true, }, nil @@ -589,7 +590,7 @@ func (h *editHeader) flush() { } type editPrinterOptions struct { - printer kubectl.ResourcePrinter + printer printers.ResourcePrinter ext string addHeader bool } diff --git a/pkg/kubectl/cmd/expose_test.go b/pkg/kubectl/cmd/expose_test.go index 331d8f89d7..fdf67367fe 100644 --- a/pkg/kubectl/cmd/expose_test.go +++ b/pkg/kubectl/cmd/expose_test.go @@ -28,8 +28,8 @@ import ( "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/client-go/rest/fake" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/kubectl" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" + "k8s.io/kubernetes/pkg/printers" ) func TestRunExposeService(t *testing.T) { @@ -460,7 +460,7 @@ func TestRunExposeService(t *testing.T) { for _, test := range tests { f, tf, codec, ns := cmdtesting.NewAPIFactory() - tf.Printer = &kubectl.JSONPrinter{} + tf.Printer = &printers.JSONPrinter{} tf.Client = &fake.RESTClient{ APIRegistry: api.Registry, NegotiatedSerializer: ns, diff --git a/pkg/kubectl/cmd/get.go b/pkg/kubectl/cmd/get.go index fb85104f7f..d11bd55b16 100644 --- a/pkg/kubectl/cmd/get.go +++ b/pkg/kubectl/cmd/get.go @@ -33,6 +33,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/util/i18n" "k8s.io/kubernetes/pkg/util/interrupt" ) @@ -93,7 +94,7 @@ func NewCmdGet(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Comman // retrieve a list of handled resources from printer as valid args validArgs, argAliases := []string{}, []string{} - p, err := f.Printer(nil, kubectl.PrintOptions{ + p, err := f.Printer(nil, printers.PrintOptions{ ColumnLabels: []string{}, }) cmdutil.CheckErr(err) @@ -300,7 +301,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [ return err } - printer, generic, err := cmdutil.PrinterForCommand(cmd) + printer, generic, err := f.PrinterForCommand(cmd) if err != nil { return err } @@ -419,7 +420,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [ // use the default printer for each object printer = nil var lastMapping *meta.RESTMapping - w := kubectl.GetNewTabWriter(out) + w := printers.GetNewTabWriter(out) filteredResourceCount := 0 if resource.MultipleTypesRequested(args) || cmdutil.MustPrintWithKinds(objs, infos, sorter) { @@ -475,7 +476,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [ } } - if resourcePrinter, found := printer.(*kubectl.HumanReadablePrinter); found { + if resourcePrinter, found := printer.(*printers.HumanReadablePrinter); found { resourceName := resourcePrinter.GetResourceKind() if mapping != nil { if resourceName == "" { diff --git a/pkg/kubectl/cmd/get_test.go b/pkg/kubectl/cmd/get_test.go index 39200512d1..7a55f9a4f8 100644 --- a/pkg/kubectl/cmd/get_test.go +++ b/pkg/kubectl/cmd/get_test.go @@ -29,6 +29,7 @@ import ( apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer/json" @@ -459,7 +460,8 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) { pods, svc, _ := testData() f, tf, codec, _ := cmdtesting.NewAPIFactory() - tf.Printer = &testPrinter{} + tf.CommandPrinter = &testPrinter{} + tf.GenericPrinter = true tf.UnstructuredClient = &fake.RESTClient{ APIRegistry: api.Registry, NegotiatedSerializer: unstructuredSerializer, @@ -486,34 +488,37 @@ func TestGetMultipleTypeObjectsAsList(t *testing.T) { cmd.Flags().Set("output", "json") cmd.Run(cmd, []string{"pods,services"}) - if tf.Printer.(*testPrinter).Objects != nil { - t.Errorf("unexpected print to default printer") + actual := tf.CommandPrinter.(*testPrinter).Objects + fn := func(obj runtime.Object) *unstructured.Unstructured { + data, err := runtime.Encode(api.Codecs.LegacyCodec(schema.GroupVersion{Version: "v1"}), obj) + if err != nil { + panic(err) + } + out := &unstructured.Unstructured{Object: make(map[string]interface{})} + if err := encjson.Unmarshal(data, &out.Object); err != nil { + panic(err) + } + return out } - out, err := runtime.Decode(codec, buf.Bytes()) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - list, err := meta.ExtractList(out) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - if errs := runtime.DecodeList(list, codec); len(errs) > 0 { - t.Fatalf("unexpected error: %v", errs) - } - if err := meta.SetList(out, list); err != nil { - t.Fatalf("unexpected error: %v", err) - } - - expected := &api.List{ - Items: []runtime.Object{ - &pods.Items[0], - &pods.Items[1], - &svc.Items[0], + expected := &unstructured.UnstructuredList{ + Object: map[string]interface{}{"kind": "List", "apiVersion": "v1", "metadata": map[string]interface{}{}, "selfLink": "", "resourceVersion": ""}, + Items: []*unstructured.Unstructured{ + fn(&pods.Items[0]), + fn(&pods.Items[1]), + fn(&svc.Items[0]), }, } - if !reflect.DeepEqual(expected, out) { - t.Errorf("unexpected output: %#v", out) + actualBytes, err := encjson.Marshal(actual[0]) + if err != nil { + t.Fatal(err) + } + expectedBytes, err := encjson.Marshal(expected) + if err != nil { + t.Fatal(err) + } + if string(actualBytes) != string(expectedBytes) { + t.Errorf("unexpected object:\n%s\n%s", expectedBytes, actualBytes) } } diff --git a/pkg/kubectl/cmd/label.go b/pkg/kubectl/cmd/label.go index 5c84b8babb..14b20b7718 100644 --- a/pkg/kubectl/cmd/label.go +++ b/pkg/kubectl/cmd/label.go @@ -39,6 +39,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/util/i18n" ) @@ -99,7 +100,7 @@ func NewCmdLabel(f cmdutil.Factory, out io.Writer) *cobra.Command { // retrieve a list of handled resources from printer as valid args validArgs, argAliases := []string{}, []string{} - p, err := f.Printer(nil, kubectl.PrintOptions{ + p, err := f.Printer(nil, printers.PrintOptions{ ColumnLabels: []string{}, }) cmdutil.CheckErr(err) diff --git a/pkg/kubectl/cmd/patch.go b/pkg/kubectl/cmd/patch.go index 6115279c39..33236fbdea 100644 --- a/pkg/kubectl/cmd/patch.go +++ b/pkg/kubectl/cmd/patch.go @@ -39,6 +39,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/util/i18n" ) @@ -81,7 +82,7 @@ func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command { // retrieve a list of handled resources from printer as valid args validArgs, argAliases := []string{}, []string{} - p, err := f.Printer(nil, kubectl.PrintOptions{ + p, err := f.Printer(nil, printers.PrintOptions{ ColumnLabels: []string{}, }) cmdutil.CheckErr(err) diff --git a/pkg/kubectl/cmd/set/set_image_test.go b/pkg/kubectl/cmd/set/set_image_test.go index a83dc71627..400903a2ba 100644 --- a/pkg/kubectl/cmd/set/set_image_test.go +++ b/pkg/kubectl/cmd/set/set_image_test.go @@ -22,16 +22,17 @@ import ( "strings" "testing" + "k8s.io/apimachinery/pkg/runtime" restclient "k8s.io/client-go/rest" "k8s.io/client-go/rest/fake" "k8s.io/kubernetes/pkg/api" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" - cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/resource" + "k8s.io/kubernetes/pkg/printers" ) func TestImageLocal(t *testing.T) { - f, tf, _, ns := cmdtesting.NewAPIFactory() + f, tf, codec, ns := cmdtesting.NewAPIFactory() tf.Client = &fake.RESTClient{ APIRegistry: api.Registry, NegotiatedSerializer: ns, @@ -47,7 +48,8 @@ func TestImageLocal(t *testing.T) { cmd := NewCmdImage(f, buf, buf) cmd.SetOutput(buf) cmd.Flags().Set("output", "name") - tf.Printer, _, _ = cmdutil.PrinterForCommand(cmd) + mapper, typer := f.Object() + tf.Printer = &printers.NamePrinter{Decoders: []runtime.Decoder{codec}, Typer: typer, Mapper: mapper} opts := ImageOptions{FilenameOptions: resource.FilenameOptions{ Filenames: []string{"../../../../examples/storage/cassandra/cassandra-controller.yaml"}}, @@ -63,7 +65,7 @@ func TestImageLocal(t *testing.T) { if err != nil { t.Fatalf("unexpected error: %v", err) } - if !strings.Contains(buf.String(), "replicationcontroller/cassandra") { + if !strings.Contains(buf.String(), "replicationcontrollers/cassandra") { t.Errorf("did not set image: %s", buf.String()) } } diff --git a/pkg/kubectl/cmd/testing/fake.go b/pkg/kubectl/cmd/testing/fake.go index 0ce1591dc5..d615e186ad 100644 --- a/pkg/kubectl/cmd/testing/fake.go +++ b/pkg/kubectl/cmd/testing/fake.go @@ -466,8 +466,8 @@ func (f *FakeFactory) NewBuilder() *resource.Builder { return nil } -func (f *FakeFactory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *kubectl.PrintOptions { - return &kubectl.PrintOptions{} +func (f *FakeFactory) DefaultResourceFilterOptions(cmd *cobra.Command, withNamespace bool) *printers.PrintOptions { + return &printers.PrintOptions{} } func (f *FakeFactory) DefaultResourceFilterFunc() kubectl.Filters { diff --git a/pkg/kubectl/history.go b/pkg/kubectl/history.go index b64a34d793..b13491fadd 100644 --- a/pkg/kubectl/history.go +++ b/pkg/kubectl/history.go @@ -20,6 +20,7 @@ import ( "bytes" "fmt" "io" + "text/tabwriter" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -30,6 +31,7 @@ import ( "k8s.io/kubernetes/pkg/apis/extensions" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" + printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" sliceutil "k8s.io/kubernetes/pkg/util/slice" ) @@ -55,6 +57,7 @@ type DeploymentHistoryViewer struct { } // ViewHistory returns a revision-to-replicaset map as the revision history of a deployment +// TODO: this should be a describer func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision int64) (string, error) { versionedClient := versionedClientsetForDeployment(h.c) deployment, err := versionedClient.Extensions().Deployments(namespace).Get(name, metav1.GetOptions{}) @@ -101,7 +104,7 @@ func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision i if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil { return "", fmt.Errorf("failed to convert podtemplate, %v", err) } - DescribePodTemplate(internalTemplate, buf) + printersinternal.DescribePodTemplate(internalTemplate, buf) return buf.String(), nil } @@ -126,6 +129,22 @@ func (h *DeploymentHistoryViewer) ViewHistory(namespace, name string, revision i }) } +// TODO: copied here until this becomes a describer +func tabbedString(f func(io.Writer) error) (string, error) { + out := new(tabwriter.Writer) + buf := &bytes.Buffer{} + out.Init(buf, 0, 8, 1, '\t', 0) + + err := f(out) + if err != nil { + return "", err + } + + out.Flush() + str := string(buf.String()) + return str, nil +} + // getChangeCause returns the change-cause annotation of the input object func getChangeCause(obj runtime.Object) string { accessor, err := meta.Accessor(obj) diff --git a/pkg/kubectl/kubectl.go b/pkg/kubectl/kubectl.go index 3f812dddf0..5b6594a3aa 100644 --- a/pkg/kubectl/kubectl.go +++ b/pkg/kubectl/kubectl.go @@ -24,7 +24,6 @@ import ( "strings" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/kubernetes/pkg/api" ) const ( @@ -35,18 +34,6 @@ type NamespaceInfo struct { Namespace string } -func listOfImages(spec *api.PodSpec) []string { - images := make([]string, 0, len(spec.Containers)) - for _, container := range spec.Containers { - images = append(images, container.Image) - } - return images -} - -func makeImageList(spec *api.PodSpec) string { - return strings.Join(listOfImages(spec), ",") -} - // ResourceShortcuts represents a structure that holds the information how to // transition from resource's shortcut to its full name. type ResourceShortcuts struct { diff --git a/pkg/kubectl/metricsutil/metrics_printer.go b/pkg/kubectl/metricsutil/metrics_printer.go index cbc67b3254..576926a6ba 100644 --- a/pkg/kubectl/metricsutil/metrics_printer.go +++ b/pkg/kubectl/metricsutil/metrics_printer.go @@ -23,7 +23,7 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metricsapi "k8s.io/heapster/metrics/apis/metrics/v1alpha1" "k8s.io/kubernetes/pkg/api" - "k8s.io/kubernetes/pkg/kubectl" + "k8s.io/kubernetes/pkg/printers" ) var ( @@ -55,7 +55,7 @@ func (printer *TopCmdPrinter) PrintNodeMetrics(metrics []metricsapi.NodeMetrics, if len(metrics) == 0 { return nil } - w := kubectl.GetNewTabWriter(printer.out) + w := printers.GetNewTabWriter(printer.out) defer w.Flush() printColumnNames(w, NodeColumns) @@ -78,7 +78,7 @@ func (printer *TopCmdPrinter) PrintPodMetrics(metrics []metricsapi.PodMetrics, p if len(metrics) == 0 { return nil } - w := kubectl.GetNewTabWriter(printer.out) + w := printers.GetNewTabWriter(printer.out) defer w.Flush() if withNamespace { diff --git a/pkg/kubectl/resource_filter.go b/pkg/kubectl/resource_filter.go index 5443274ae6..34b5dba915 100644 --- a/pkg/kubectl/resource_filter.go +++ b/pkg/kubectl/resource_filter.go @@ -20,12 +20,13 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/printers" ) // FilterFunc is a function that knows how to filter a specific resource kind. // It receives a generic runtime.Object which must be type-checked by the function. // Returns a boolean value true if a resource is filtered, or false otherwise. -type FilterFunc func(runtime.Object, PrintOptions) bool +type FilterFunc func(runtime.Object, printers.PrintOptions) bool // Filters is a collection of filter funcs type Filters []FilterFunc @@ -38,7 +39,7 @@ func NewResourceFilter() Filters { // filterPods returns true if a pod should be skipped. // defaults to true for terminated pods -func filterPods(obj runtime.Object, options PrintOptions) bool { +func filterPods(obj runtime.Object, options printers.PrintOptions) bool { switch p := obj.(type) { case *v1.Pod: reason := string(p.Status.Phase) @@ -57,7 +58,7 @@ func filterPods(obj runtime.Object, options PrintOptions) bool { } // Filter loops through a collection of FilterFuncs until it finds one that can filter the given resource -func (f Filters) Filter(obj runtime.Object, opts *PrintOptions) (bool, error) { +func (f Filters) Filter(obj runtime.Object, opts *printers.PrintOptions) (bool, error) { // check if the object is unstructured. If so, let's attempt to convert it to a type we can understand // before apply filter func. obj, _ = DecodeUnknownObject(obj) diff --git a/pkg/kubectl/rollback.go b/pkg/kubectl/rollback.go index 16c174f0f4..32f9140669 100644 --- a/pkg/kubectl/rollback.go +++ b/pkg/kubectl/rollback.go @@ -33,6 +33,7 @@ import ( externalextensions "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" clientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" deploymentutil "k8s.io/kubernetes/pkg/controller/deployment/util" + printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" sliceutil "k8s.io/kubernetes/pkg/util/slice" ) @@ -170,7 +171,7 @@ func simpleDryRun(deployment *extensions.Deployment, c clientset.Interface, toRe if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil { return "", fmt.Errorf("failed to convert podtemplate, %v", err) } - DescribePodTemplate(internalTemplate, buf) + printersinternal.DescribePodTemplate(internalTemplate, buf) return buf.String(), nil } @@ -188,6 +189,6 @@ func simpleDryRun(deployment *extensions.Deployment, c clientset.Interface, toRe if err := v1.Convert_v1_PodTemplateSpec_To_api_PodTemplateSpec(template, internalTemplate, nil); err != nil { return "", fmt.Errorf("failed to convert podtemplate, %v", err) } - DescribePodTemplate(internalTemplate, buf) + printersinternal.DescribePodTemplate(internalTemplate, buf) return buf.String(), nil } diff --git a/pkg/kubectl/sorting_printer.go b/pkg/kubectl/sorting_printer.go index 381998c9f1..6243b6c0e6 100644 --- a/pkg/kubectl/sorting_printer.go +++ b/pkg/kubectl/sorting_printer.go @@ -31,13 +31,14 @@ import ( "k8s.io/client-go/util/integer" "k8s.io/client-go/util/jsonpath" "k8s.io/kubernetes/pkg/api/v1" + "k8s.io/kubernetes/pkg/printers" ) // Sorting printer sorts list types before delegating to another printer. // Non-list types are simply passed through type SortingPrinter struct { SortField string - Delegate ResourcePrinter + Delegate printers.ResourcePrinter Decoder runtime.Decoder } @@ -101,7 +102,7 @@ func SortObjects(decoder runtime.Decoder, objs []runtime.Object, fieldInput stri } } - field, err := massageJSONPath(fieldInput) + field, err := printers.RelaxedJSONPathExpression(fieldInput) if err != nil { return nil, err }