wire printflags through set cmds

This commit is contained in:
juanvallejo 2018-04-04 16:23:33 -04:00
parent f79ab9c1ee
commit b8dc20646c
No known key found for this signature in database
GPG Key ID: 7D2C958002D6448D
8 changed files with 259 additions and 78 deletions

View File

@ -20,6 +20,8 @@ import (
"fmt" "fmt"
"io" "io"
"k8s.io/kubernetes/pkg/printers"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@ -36,12 +38,13 @@ import (
type ImageOptions struct { type ImageOptions struct {
resource.FilenameOptions resource.FilenameOptions
PrintFlags *printers.PrintFlags
Infos []*resource.Info Infos []*resource.Info
Selector string Selector string
Out io.Writer Out io.Writer
Err io.Writer Err io.Writer
DryRun bool DryRun bool
ShortOutput bool
All bool All bool
Record bool Record bool
Output string Output string
@ -50,6 +53,8 @@ type ImageOptions struct {
Cmd *cobra.Command Cmd *cobra.Command
ResolveImage func(in string) (string, error) ResolveImage func(in string) (string, error)
PrintObj func(runtime.Object) error
UpdatePodSpecForObject func(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error) UpdatePodSpecForObject func(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error)
Resources []string Resources []string
ContainerImages map[string]string ContainerImages map[string]string
@ -81,6 +86,8 @@ var (
func NewCmdImage(f cmdutil.Factory, out, err io.Writer) *cobra.Command { func NewCmdImage(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
options := &ImageOptions{ options := &ImageOptions{
PrintFlags: printers.NewPrintFlags("image updated"),
Out: out, Out: out,
Err: err, Err: err,
} }
@ -98,7 +105,8 @@ func NewCmdImage(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
}, },
} }
cmdutil.AddPrinterFlags(cmd) options.PrintFlags.AddFlags(cmd)
usage := "identifying the resource to get from a server." usage := "identifying the resource to get from a server."
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage) cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all resources, including uninitialized ones, in the namespace of the specified resource types") cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all resources, including uninitialized ones, in the namespace of the specified resource types")
@ -112,7 +120,6 @@ func NewCmdImage(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
o.ShortOutput = cmdutil.GetFlagString(cmd, "output") == "name"
o.Record = cmdutil.GetRecordFlag(cmd) o.Record = cmdutil.GetRecordFlag(cmd)
o.ChangeCause = f.Command(cmd, false) o.ChangeCause = f.Command(cmd, false)
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetDryRunFlag(cmd)
@ -120,6 +127,17 @@ func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
o.ResolveImage = f.ResolveImage o.ResolveImage = f.ResolveImage
o.Cmd = cmd o.Cmd = cmd
o.PrintFlags.Complete(o.DryRun)
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
return err
}
o.PrintObj = func(obj runtime.Object) error {
return printer.PrintObj(obj, o.Out)
}
cmdNamespace, enforceNamespace, err := f.DefaultNamespace() cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil { if err != nil {
return err return err
@ -232,15 +250,15 @@ func (o *ImageOptions) Run() error {
continue continue
} }
// no changes if o.Local || o.DryRun {
if string(patch.Patch) == "{}" || len(patch.Patch) == 0 { if err := o.PrintObj(patch.Info.AsVersioned()); err != nil {
return err
}
continue continue
} }
if o.Local || o.DryRun { // no changes
if err := cmdutil.PrintObject(o.Cmd, patch.Info.AsVersioned(), o.Out); err != nil { if string(patch.Patch) == "{}" || len(patch.Patch) == 0 {
return err
}
continue continue
} }
@ -263,13 +281,9 @@ func (o *ImageOptions) Run() error {
info.Refresh(obj, true) info.Refresh(obj, true)
if len(o.Output) > 0 { if err := o.PrintObj(info.AsVersioned()); err != nil {
if err := cmdutil.PrintObject(o.Cmd, info.AsVersioned(), o.Out); err != nil { return err
return err
}
continue
} }
cmdutil.PrintSuccess(o.ShortOutput, o.Out, info.Object, o.DryRun, "image updated")
} }
return utilerrors.NewAggregate(allErrs) return utilerrors.NewAggregate(allErrs)
} }

View File

@ -25,6 +25,8 @@ import (
"strings" "strings"
"testing" "testing"
"k8s.io/kubernetes/pkg/printers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
appsv1beta1 "k8s.io/api/apps/v1beta1" appsv1beta1 "k8s.io/api/apps/v1beta1"
@ -61,14 +63,23 @@ func TestImageLocal(t *testing.T) {
tf.Namespace = "test" tf.Namespace = "test"
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}}
outputFormat := "name"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdImage(tf, buf, buf) cmd := NewCmdImage(tf, buf, buf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("output", "name") cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true") cmd.Flags().Set("local", "true")
opts := ImageOptions{FilenameOptions: resource.FilenameOptions{ opts := ImageOptions{
Filenames: []string{"../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}}, PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags("", false),
OutputFormat: &outputFormat,
},
FilenameOptions: resource.FilenameOptions{
Filenames: []string{"../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}},
Out: buf, Out: buf,
Local: true} Local: true}
err := opts.Complete(tf, cmd, []string{"cassandra=thingy"}) err := opts.Complete(tf, cmd, []string{"cassandra=thingy"})
@ -87,6 +98,11 @@ func TestImageLocal(t *testing.T) {
} }
func TestSetImageValidation(t *testing.T) { func TestSetImageValidation(t *testing.T) {
printFlags := &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags("", false),
}
testCases := []struct { testCases := []struct {
name string name string
imageOptions *ImageOptions imageOptions *ImageOptions
@ -94,13 +110,14 @@ func TestSetImageValidation(t *testing.T) {
}{ }{
{ {
name: "test resource < 1 and filenames empty", name: "test resource < 1 and filenames empty",
imageOptions: &ImageOptions{}, imageOptions: &ImageOptions{PrintFlags: printFlags},
expectErr: "[one or more resources must be specified as <resource> <name> or <resource>/<name>, at least one image update is required]", expectErr: "[one or more resources must be specified as <resource> <name> or <resource>/<name>, at least one image update is required]",
}, },
{ {
name: "test containerImages < 1", name: "test containerImages < 1",
imageOptions: &ImageOptions{ imageOptions: &ImageOptions{
Resources: []string{"a", "b", "c"}, PrintFlags: printFlags,
Resources: []string{"a", "b", "c"},
FilenameOptions: resource.FilenameOptions{ FilenameOptions: resource.FilenameOptions{
Filenames: []string{"testFile"}, Filenames: []string{"testFile"},
@ -111,7 +128,8 @@ func TestSetImageValidation(t *testing.T) {
{ {
name: "test containerImages > 1 and all containers are already specified by *", name: "test containerImages > 1 and all containers are already specified by *",
imageOptions: &ImageOptions{ imageOptions: &ImageOptions{
Resources: []string{"a", "b", "c"}, PrintFlags: printFlags,
Resources: []string{"a", "b", "c"},
FilenameOptions: resource.FilenameOptions{ FilenameOptions: resource.FilenameOptions{
Filenames: []string{"testFile"}, Filenames: []string{"testFile"},
}, },
@ -125,7 +143,8 @@ func TestSetImageValidation(t *testing.T) {
{ {
name: "success case", name: "success case",
imageOptions: &ImageOptions{ imageOptions: &ImageOptions{
Resources: []string{"a", "b", "c"}, PrintFlags: printFlags,
Resources: []string{"a", "b", "c"},
FilenameOptions: resource.FilenameOptions{ FilenameOptions: resource.FilenameOptions{
Filenames: []string{"testFile"}, Filenames: []string{"testFile"},
}, },
@ -166,14 +185,23 @@ func TestSetMultiResourcesImageLocal(t *testing.T) {
tf.Namespace = "test" tf.Namespace = "test"
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}}
outputFormat := "name"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdImage(tf, buf, buf) cmd := NewCmdImage(tf, buf, buf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("output", "name") cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true") cmd.Flags().Set("local", "true")
opts := ImageOptions{FilenameOptions: resource.FilenameOptions{ opts := ImageOptions{
Filenames: []string{"../../../../test/fixtures/pkg/kubectl/cmd/set/multi-resource-yaml.yaml"}}, PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags("", false),
OutputFormat: &outputFormat,
},
FilenameOptions: resource.FilenameOptions{
Filenames: []string{"../../../../test/fixtures/pkg/kubectl/cmd/set/multi-resource-yaml.yaml"}},
Out: buf, Out: buf,
Local: true} Local: true}
err := opts.Complete(tf, cmd, []string{"*=thingy"}) err := opts.Complete(tf, cmd, []string{"*=thingy"})
@ -552,11 +580,21 @@ func TestSetImageRemote(t *testing.T) {
}), }),
VersionedAPIPath: path.Join(input.apiPrefix, testapi.Default.GroupVersion().String()), VersionedAPIPath: path.Join(input.apiPrefix, testapi.Default.GroupVersion().String()),
} }
outputFormat := "yaml"
out := new(bytes.Buffer) out := new(bytes.Buffer)
cmd := NewCmdImage(tf, out, out) cmd := NewCmdImage(tf, out, out)
cmd.SetOutput(out) cmd.SetOutput(out)
cmd.Flags().Set("output", "yaml") cmd.Flags().Set("output", outputFormat)
opts := ImageOptions{ opts := ImageOptions{
PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags("", false),
OutputFormat: &outputFormat,
},
Out: out, Out: out,
Local: false} Local: false}
err := opts.Complete(tf, cmd, input.args) err := opts.Complete(tf, cmd, input.args)

View File

@ -21,6 +21,8 @@ import (
"io" "io"
"strings" "strings"
"k8s.io/kubernetes/pkg/printers"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
@ -61,6 +63,8 @@ var (
type ResourcesOptions struct { type ResourcesOptions struct {
resource.FilenameOptions resource.FilenameOptions
PrintFlags *printers.PrintFlags
Infos []*resource.Info Infos []*resource.Info
Out io.Writer Out io.Writer
Err io.Writer Err io.Writer
@ -73,6 +77,10 @@ type ResourcesOptions struct {
Local bool Local bool
Cmd *cobra.Command Cmd *cobra.Command
DryRun bool
PrintObj func(runtime.Object) error
Limits string Limits string
Requests string Requests string
ResourceRequirements v1.ResourceRequirements ResourceRequirements v1.ResourceRequirements
@ -85,6 +93,8 @@ type ResourcesOptions struct {
// pod templates are selected by default. // pod templates are selected by default.
func NewResourcesOptions(out io.Writer, errOut io.Writer) *ResourcesOptions { func NewResourcesOptions(out io.Writer, errOut io.Writer) *ResourcesOptions {
return &ResourcesOptions{ return &ResourcesOptions{
PrintFlags: printers.NewPrintFlags("resource requirements updated"),
Out: out, Out: out,
Err: errOut, Err: errOut,
ContainerSelector: "*", ContainerSelector: "*",
@ -112,7 +122,8 @@ func NewCmdResources(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.
}, },
} }
cmdutil.AddPrinterFlags(cmd) options.PrintFlags.AddFlags(cmd)
//usage := "Filename, directory, or URL to a file identifying the resource to get from the server" //usage := "Filename, directory, or URL to a file identifying the resource to get from the server"
//kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage) //kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
usage := "identifying the resource to get from a server." usage := "identifying the resource to get from a server."
@ -135,6 +146,18 @@ func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
o.Record = cmdutil.GetRecordFlag(cmd) o.Record = cmdutil.GetRecordFlag(cmd)
o.ChangeCause = f.Command(cmd, false) o.ChangeCause = f.Command(cmd, false)
o.Cmd = cmd o.Cmd = cmd
o.DryRun = cmdutil.GetDryRunFlag(o.Cmd)
o.PrintFlags.Complete(o.DryRun)
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
return err
}
o.PrintObj = func(obj runtime.Object) error {
return printer.PrintObj(obj, o.Out)
}
cmdNamespace, enforceNamespace, err := f.DefaultNamespace() cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil { if err != nil {
@ -238,8 +261,8 @@ func (o *ResourcesOptions) Run() error {
continue continue
} }
if o.Local || cmdutil.GetDryRunFlag(o.Cmd) { if o.Local || o.DryRun {
if err := cmdutil.PrintObject(o.Cmd, patch.Info.AsVersioned(), o.Out); err != nil { if err := o.PrintObj(patch.Info.AsVersioned()); err != nil {
return err return err
} }
continue continue
@ -262,14 +285,9 @@ func (o *ResourcesOptions) Run() error {
} }
info.Refresh(obj, true) info.Refresh(obj, true)
shortOutput := o.Output == "name" if err := o.PrintObj(info.AsVersioned()); err != nil {
if len(o.Output) > 0 && !shortOutput { return err
if err := cmdutil.PrintObject(o.Cmd, info.AsVersioned(), o.Out); err != nil {
return err
}
continue
} }
cmdutil.PrintSuccess(shortOutput, o.Out, info.Object, false, "resource requirements updated")
} }
return utilerrors.NewAggregate(allErrs) return utilerrors.NewAggregate(allErrs)
} }

View File

@ -25,6 +25,8 @@ import (
"strings" "strings"
"testing" "testing"
"k8s.io/kubernetes/pkg/printers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
appsv1beta1 "k8s.io/api/apps/v1beta1" appsv1beta1 "k8s.io/api/apps/v1beta1"
@ -60,14 +62,23 @@ func TestResourcesLocal(t *testing.T) {
tf.Namespace = "test" tf.Namespace = "test"
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}}
outputFormat := "name"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdResources(tf, buf, buf) cmd := NewCmdResources(tf, buf, buf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("output", "name") cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true") cmd.Flags().Set("local", "true")
opts := ResourcesOptions{FilenameOptions: resource.FilenameOptions{ opts := ResourcesOptions{
Filenames: []string{"../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}}, PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags("", false),
OutputFormat: &outputFormat,
},
FilenameOptions: resource.FilenameOptions{
Filenames: []string{"../../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}},
Out: buf, Out: buf,
Local: true, Local: true,
Limits: "cpu=200m,memory=512Mi", Limits: "cpu=200m,memory=512Mi",
@ -105,14 +116,23 @@ func TestSetMultiResourcesLimitsLocal(t *testing.T) {
tf.Namespace = "test" tf.Namespace = "test"
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}}
outputFormat := "name"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdResources(tf, buf, buf) cmd := NewCmdResources(tf, buf, buf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("output", "name") cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true") cmd.Flags().Set("local", "true")
opts := ResourcesOptions{FilenameOptions: resource.FilenameOptions{ opts := ResourcesOptions{
Filenames: []string{"../../../../test/fixtures/pkg/kubectl/cmd/set/multi-resource-yaml.yaml"}}, PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags("", false),
OutputFormat: &outputFormat,
},
FilenameOptions: resource.FilenameOptions{
Filenames: []string{"../../../../test/fixtures/pkg/kubectl/cmd/set/multi-resource-yaml.yaml"}},
Out: buf, Out: buf,
Local: true, Local: true,
Limits: "cpu=200m,memory=512Mi", Limits: "cpu=200m,memory=512Mi",
@ -478,11 +498,21 @@ func TestSetResourcesRemote(t *testing.T) {
}), }),
VersionedAPIPath: path.Join(input.apiPrefix, testapi.Default.GroupVersion().String()), VersionedAPIPath: path.Join(input.apiPrefix, testapi.Default.GroupVersion().String()),
} }
outputFormat := "yaml"
buf := new(bytes.Buffer) buf := new(bytes.Buffer)
cmd := NewCmdResources(tf, buf, buf) cmd := NewCmdResources(tf, buf, buf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("output", "yaml") cmd.Flags().Set("output", outputFormat)
opts := ResourcesOptions{ opts := ResourcesOptions{
PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags("", false),
OutputFormat: &outputFormat,
},
Out: buf, Out: buf,
Limits: "cpu=200m,memory=512Mi", Limits: "cpu=200m,memory=512Mi",
ContainerSelector: "*"} ContainerSelector: "*"}

View File

@ -20,6 +20,8 @@ import (
"fmt" "fmt"
"io" "io"
"k8s.io/kubernetes/pkg/printers"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
@ -38,6 +40,8 @@ import (
type SelectorOptions struct { type SelectorOptions struct {
fileOptions resource.FilenameOptions fileOptions resource.FilenameOptions
PrintFlags *printers.PrintFlags
local bool local bool
dryrun bool dryrun bool
all bool all bool
@ -52,6 +56,8 @@ type SelectorOptions struct {
PrintObject func(obj runtime.Object) error PrintObject func(obj runtime.Object) error
ClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error) ClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
PrintObj func(runtime.Object) error
builder *resource.Builder builder *resource.Builder
mapper meta.RESTMapper mapper meta.RESTMapper
} }
@ -73,6 +79,8 @@ var (
// NewCmdSelector is the "set selector" command. // NewCmdSelector is the "set selector" command.
func NewCmdSelector(f cmdutil.Factory, out io.Writer) *cobra.Command { func NewCmdSelector(f cmdutil.Factory, out io.Writer) *cobra.Command {
options := &SelectorOptions{ options := &SelectorOptions{
PrintFlags: printers.NewPrintFlags("selector updated"),
out: out, out: out,
} }
@ -88,7 +96,9 @@ func NewCmdSelector(f cmdutil.Factory, out io.Writer) *cobra.Command {
cmdutil.CheckErr(options.RunSelector()) cmdutil.CheckErr(options.RunSelector())
}, },
} }
cmdutil.AddPrinterFlags(cmd)
options.PrintFlags.AddFlags(cmd)
cmd.Flags().Bool("all", false, "Select all resources, including uninitialized ones, in the namespace of the specified resource types") cmd.Flags().Bool("all", false, "Select all resources, including uninitialized ones, in the namespace of the specified resource types")
cmd.Flags().Bool("local", false, "If true, set selector will NOT contact api-server but run locally.") cmd.Flags().Bool("local", false, "If true, set selector will NOT contact api-server but run locally.")
cmd.Flags().String("resource-version", "", "If non-empty, the selectors update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource.") cmd.Flags().String("resource-version", "", "If non-empty, the selectors update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource.")
@ -109,6 +119,8 @@ func (o *SelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
o.dryrun = cmdutil.GetDryRunFlag(cmd) o.dryrun = cmdutil.GetDryRunFlag(cmd)
o.output = cmdutil.GetFlagString(cmd, "output") o.output = cmdutil.GetFlagString(cmd, "output")
o.PrintFlags.Complete(o.dryrun)
cmdNamespace, enforceNamespace, err := f.DefaultNamespace() cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil { if err != nil {
return err return err
@ -146,8 +158,13 @@ func (o *SelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
} }
} }
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
return err
}
o.PrintObject = func(obj runtime.Object) error { o.PrintObject = func(obj runtime.Object) error {
return cmdutil.PrintObject(cmd, obj, o.out) return printer.PrintObj(obj, o.out)
} }
o.ClientForMapping = func(mapping *meta.RESTMapping) (resource.RESTClient, error) { o.ClientForMapping = func(mapping *meta.RESTMapping) (resource.RESTClient, error) {
return f.ClientForMapping(mapping) return f.ClientForMapping(mapping)
@ -208,13 +225,7 @@ func (o *SelectorOptions) RunSelector() error {
} }
info.Refresh(patched, true) info.Refresh(patched, true)
return o.PrintObject(patch.Info.AsVersioned())
shortOutput := o.output == "name"
if len(o.output) > 0 && !shortOutput {
return o.PrintObject(patched)
}
cmdutil.PrintSuccess(shortOutput, o.out, info.Object, o.dryrun, "selector updated")
return nil
}) })
} }

View File

@ -21,6 +21,8 @@ import (
"fmt" "fmt"
"io" "io"
"k8s.io/kubernetes/pkg/printers"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
@ -54,6 +56,8 @@ var (
// serviceAccountConfig encapsulates the data required to perform the operation. // serviceAccountConfig encapsulates the data required to perform the operation.
type serviceAccountConfig struct { type serviceAccountConfig struct {
PrintFlags *printers.PrintFlags
fileNameOptions resource.FilenameOptions fileNameOptions resource.FilenameOptions
out io.Writer out io.Writer
err io.Writer err io.Writer
@ -68,11 +72,15 @@ type serviceAccountConfig struct {
updatePodSpecForObject func(runtime.Object, func(*v1.PodSpec) error) (bool, error) updatePodSpecForObject func(runtime.Object, func(*v1.PodSpec) error) (bool, error)
infos []*resource.Info infos []*resource.Info
serviceAccountName string serviceAccountName string
PrintObj func(runtime.Object) error
} }
// NewCmdServiceAccount returns the "set serviceaccount" command. // NewCmdServiceAccount returns the "set serviceaccount" command.
func NewCmdServiceAccount(f cmdutil.Factory, out, err io.Writer) *cobra.Command { func NewCmdServiceAccount(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
saConfig := &serviceAccountConfig{ saConfig := &serviceAccountConfig{
PrintFlags: printers.NewPrintFlags("serviceaccount updated"),
out: out, out: out,
err: err, err: err,
} }
@ -89,7 +97,8 @@ func NewCmdServiceAccount(f cmdutil.Factory, out, err io.Writer) *cobra.Command
cmdutil.CheckErr(saConfig.Run()) cmdutil.CheckErr(saConfig.Run())
}, },
} }
cmdutil.AddPrinterFlags(cmd)
saConfig.PrintFlags.AddFlags(cmd)
usage := "identifying the resource to get from a server." usage := "identifying the resource to get from a server."
cmdutil.AddFilenameOptionFlags(cmd, &saConfig.fileNameOptions, usage) cmdutil.AddFilenameOptionFlags(cmd, &saConfig.fileNameOptions, usage)
@ -111,6 +120,17 @@ func (saConfig *serviceAccountConfig) Complete(f cmdutil.Factory, cmd *cobra.Com
saConfig.updatePodSpecForObject = f.UpdatePodSpecForObject saConfig.updatePodSpecForObject = f.UpdatePodSpecForObject
saConfig.cmd = cmd saConfig.cmd = cmd
saConfig.PrintFlags.Complete(saConfig.dryRun)
printer, err := saConfig.PrintFlags.ToPrinter()
if err != nil {
return err
}
saConfig.PrintObj = func(obj runtime.Object) error {
return printer.PrintObj(obj, saConfig.out)
}
cmdNamespace, enforceNamespace, err := f.DefaultNamespace() cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil { if err != nil {
return err return err
@ -151,6 +171,7 @@ func (saConfig *serviceAccountConfig) Run() error {
}) })
return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.Object) return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.Object)
} }
patches := CalculatePatches(saConfig.infos, cmdutil.InternalVersionJSONEncoder(), patchFn) patches := CalculatePatches(saConfig.infos, cmdutil.InternalVersionJSONEncoder(), patchFn)
for _, patch := range patches { for _, patch := range patches {
info := patch.Info info := patch.Info
@ -159,7 +180,7 @@ func (saConfig *serviceAccountConfig) Run() error {
continue continue
} }
if saConfig.local || saConfig.dryRun { if saConfig.local || saConfig.dryRun {
if err := cmdutil.PrintObject(saConfig.cmd, patch.Info.AsVersioned(), saConfig.out); err != nil { if err := saConfig.PrintObj(patch.Info.AsVersioned()); err != nil {
return err return err
} }
continue continue
@ -177,13 +198,10 @@ func (saConfig *serviceAccountConfig) Run() error {
} }
} }
} }
if len(saConfig.output) > 0 {
if err := cmdutil.PrintObject(saConfig.cmd, info.AsVersioned(), saConfig.out); err != nil { if err := saConfig.PrintObj(info.AsVersioned()); err != nil {
return err return err
}
continue
} }
cmdutil.PrintSuccess(saConfig.shortOutput, saConfig.out, info.Object, saConfig.dryRun, "serviceaccount updated")
} }
return utilerrors.NewAggregate(patchErrs) return utilerrors.NewAggregate(patchErrs)
} }

View File

@ -25,6 +25,8 @@ import (
"path" "path"
"testing" "testing"
"k8s.io/kubernetes/pkg/printers"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
appsv1 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
appsv1beta1 "k8s.io/api/apps/v1beta1" appsv1beta1 "k8s.io/api/apps/v1beta1"
@ -77,15 +79,25 @@ func TestSetServiceAccountLocal(t *testing.T) {
return nil, nil return nil, nil
}), }),
} }
outputFormat := "yaml"
tf.Namespace = "test" tf.Namespace = "test"
out := new(bytes.Buffer) out := new(bytes.Buffer)
cmd := NewCmdServiceAccount(tf, out, out) cmd := NewCmdServiceAccount(tf, out, out)
cmd.SetOutput(out) cmd.SetOutput(out)
cmd.Flags().Set("output", "yaml") cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true") cmd.Flags().Set("local", "true")
testapi.Default = testapi.Groups[input.apiGroup] testapi.Default = testapi.Groups[input.apiGroup]
saConfig := serviceAccountConfig{fileNameOptions: resource.FilenameOptions{ saConfig := serviceAccountConfig{
Filenames: []string{input.yaml}}, PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags("", false),
OutputFormat: &outputFormat,
},
fileNameOptions: resource.FilenameOptions{
Filenames: []string{input.yaml}},
out: out, out: out,
local: true} local: true}
err := saConfig.Complete(tf, cmd, []string{serviceAccount}) err := saConfig.Complete(tf, cmd, []string{serviceAccount})
@ -114,13 +126,22 @@ func TestSetServiceAccountMultiLocal(t *testing.T) {
tf.Namespace = "test" tf.Namespace = "test"
tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}} tf.ClientConfigVal = &restclient.Config{ContentConfig: restclient.ContentConfig{GroupVersion: &schema.GroupVersion{Version: ""}}}
outputFormat := "name"
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdServiceAccount(tf, buf, buf) cmd := NewCmdServiceAccount(tf, buf, buf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("output", "name") cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true") cmd.Flags().Set("local", "true")
opts := serviceAccountConfig{fileNameOptions: resource.FilenameOptions{ opts := serviceAccountConfig{
Filenames: []string{"../../../../test/fixtures/pkg/kubectl/cmd/set/multi-resource-yaml.yaml"}}, PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags("", false),
OutputFormat: &outputFormat,
},
fileNameOptions: resource.FilenameOptions{
Filenames: []string{"../../../../test/fixtures/pkg/kubectl/cmd/set/multi-resource-yaml.yaml"}},
out: buf, out: buf,
local: true} local: true}
@ -349,11 +370,21 @@ func TestSetServiceAccountRemote(t *testing.T) {
}), }),
VersionedAPIPath: path.Join(input.apiPrefix, testapi.Default.GroupVersion().String()), VersionedAPIPath: path.Join(input.apiPrefix, testapi.Default.GroupVersion().String()),
} }
outputFormat := "yaml"
out := new(bytes.Buffer) out := new(bytes.Buffer)
cmd := NewCmdServiceAccount(tf, out, out) cmd := NewCmdServiceAccount(tf, out, out)
cmd.SetOutput(out) cmd.SetOutput(out)
cmd.Flags().Set("output", "yaml") cmd.Flags().Set("output", outputFormat)
saConfig := serviceAccountConfig{ saConfig := serviceAccountConfig{
PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags("", false),
OutputFormat: &outputFormat,
},
out: out, out: out,
local: false} local: false}
err := saConfig.Complete(tf, cmd, input.args) err := saConfig.Complete(tf, cmd, input.args)
@ -385,12 +416,22 @@ func TestServiceAccountValidation(t *testing.T) {
return nil, nil return nil, nil
}), }),
} }
outputFormat := ""
tf.Namespace = "test" tf.Namespace = "test"
out := bytes.NewBuffer([]byte{}) out := bytes.NewBuffer([]byte{})
cmd := NewCmdServiceAccount(tf, out, out) cmd := NewCmdServiceAccount(tf, out, out)
cmd.SetOutput(out) cmd.SetOutput(out)
saConfig := &serviceAccountConfig{} saConfig := &serviceAccountConfig{
PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags("", false),
OutputFormat: &outputFormat,
},
}
err := saConfig.Complete(tf, cmd, input.args) err := saConfig.Complete(tf, cmd, input.args)
assert.EqualError(t, err, input.errorString) assert.EqualError(t, err, input.errorString)
}) })

View File

@ -21,6 +21,8 @@ import (
"io" "io"
"strings" "strings"
"k8s.io/kubernetes/pkg/printers"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
@ -54,6 +56,8 @@ type updateSubjects func(existings []rbac.Subject, targets []rbac.Subject) (bool
// SubjectOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of // SubjectOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of
// referencing the cmd.Flags // referencing the cmd.Flags
type SubjectOptions struct { type SubjectOptions struct {
PrintFlags *printers.PrintFlags
resource.FilenameOptions resource.FilenameOptions
Infos []*resource.Info Infos []*resource.Info
@ -70,11 +74,13 @@ type SubjectOptions struct {
Groups []string Groups []string
ServiceAccounts []string ServiceAccounts []string
PrintObject func(obj runtime.Object, out io.Writer) error PrintObject func(obj runtime.Object) error
} }
func NewCmdSubject(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { func NewCmdSubject(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command {
options := &SubjectOptions{ options := &SubjectOptions{
PrintFlags: printers.NewPrintFlags("subjects updated"),
Out: out, Out: out,
Err: errOut, Err: errOut,
} }
@ -92,7 +98,8 @@ func NewCmdSubject(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Co
}, },
} }
cmdutil.AddPrinterFlags(cmd) options.PrintFlags.AddFlags(cmd)
usage := "the resource to update the subjects" usage := "the resource to update the subjects"
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage) cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all resources, including uninitialized ones, in the namespace of the specified resource types") cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all resources, including uninitialized ones, in the namespace of the specified resource types")
@ -109,8 +116,16 @@ func NewCmdSubject(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Co
func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
o.Output = cmdutil.GetFlagString(cmd, "output") o.Output = cmdutil.GetFlagString(cmd, "output")
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetDryRunFlag(cmd)
o.PrintObject = func(obj runtime.Object, out io.Writer) error {
return cmdutil.PrintObject(cmd, obj, out) o.PrintFlags.Complete(o.DryRun)
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
return err
}
o.PrintObject = func(obj runtime.Object) error {
return printer.PrintObj(obj, o.Out)
} }
cmdNamespace, enforceNamespace, err := f.DefaultNamespace() cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
@ -236,7 +251,7 @@ func (o *SubjectOptions) Run(f cmdutil.Factory, fn updateSubjects) error {
} }
if o.Local || o.DryRun { if o.Local || o.DryRun {
if err := o.PrintObject(info.Object, o.Out); err != nil { if err := o.PrintObject(info.Object); err != nil {
return err return err
} }
continue continue
@ -249,11 +264,7 @@ func (o *SubjectOptions) Run(f cmdutil.Factory, fn updateSubjects) error {
} }
info.Refresh(obj, true) info.Refresh(obj, true)
shortOutput := o.Output == "name" return o.PrintObject(info.AsVersioned())
if len(o.Output) > 0 && !shortOutput {
return o.PrintObject(info.AsVersioned(), o.Out)
}
cmdutil.PrintSuccess(shortOutput, o.Out, info.Object, false, "subjects updated")
} }
return utilerrors.NewAggregate(allErrs) return utilerrors.NewAggregate(allErrs)
} }