use recordFlags

This commit is contained in:
David Eads 2018-04-19 08:32:15 -04:00
parent b1357da473
commit 484d81ab01
18 changed files with 318 additions and 237 deletions

View File

@ -196,6 +196,7 @@ go_test(
"//pkg/kubectl/cmd/testing:go_default_library", "//pkg/kubectl/cmd/testing:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library", "//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/cmd/util/openapi:go_default_library", "//pkg/kubectl/cmd/util/openapi:go_default_library",
"//pkg/kubectl/genericclioptions:go_default_library",
"//pkg/kubectl/plugins:go_default_library", "//pkg/kubectl/plugins:go_default_library",
"//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/resource:go_default_library",
"//pkg/kubectl/scheme:go_default_library", "//pkg/kubectl/scheme:go_default_library",

View File

@ -103,11 +103,13 @@ func NewAnnotateOptions(out io.Writer) *AnnotateOptions {
return &AnnotateOptions{ return &AnnotateOptions{
out: out, out: out,
RecordFlags: genericclioptions.NewRecordFlags(), RecordFlags: genericclioptions.NewRecordFlags(),
Recorder: genericclioptions.NoopRecorder{},
} }
} }
func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command { func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command {
options := NewAnnotateOptions(out) o := NewAnnotateOptions(out)
validArgs := cmdutil.ValidArgList(f) validArgs := cmdutil.ValidArgList(f)
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -117,30 +119,30 @@ func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command {
Long: annotateLong + "\n\n" + cmdutil.ValidResourceTypeList(f), Long: annotateLong + "\n\n" + cmdutil.ValidResourceTypeList(f),
Example: annotateExample, Example: annotateExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
if err := options.Complete(f, cmd, args); err != nil { if err := o.Complete(f, cmd, args); err != nil {
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, "%v", err)) cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, "%v", err))
} }
if err := options.Validate(); err != nil { if err := o.Validate(); err != nil {
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, "%v", err)) cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, "%v", err))
} }
cmdutil.CheckErr(options.RunAnnotate(f, cmd)) cmdutil.CheckErr(o.RunAnnotate(f, cmd))
}, },
ValidArgs: validArgs, ValidArgs: validArgs,
ArgAliases: kubectl.ResourceAliases(validArgs), ArgAliases: kubectl.ResourceAliases(validArgs),
} }
// bind flag structs // bind flag structs
options.RecordFlags.AddFlags(cmd) o.RecordFlags.AddFlags(cmd)
cmdutil.AddPrinterFlags(cmd) cmdutil.AddPrinterFlags(cmd)
cmdutil.AddIncludeUninitializedFlag(cmd) cmdutil.AddIncludeUninitializedFlag(cmd)
cmd.Flags().BoolVar(&options.overwrite, "overwrite", options.overwrite, "If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations.") cmd.Flags().BoolVar(&o.overwrite, "overwrite", o.overwrite, "If true, allow annotations to be overwritten, otherwise reject annotation updates that overwrite existing annotations.")
cmd.Flags().BoolVar(&options.local, "local", options.local, "If true, annotation will NOT contact api-server but run locally.") cmd.Flags().BoolVar(&o.local, "local", o.local, "If true, annotation will NOT contact api-server but run locally.")
cmd.Flags().StringVarP(&options.selector, "selector", "l", options.selector, "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2).") cmd.Flags().StringVarP(&o.selector, "selector", "l", o.selector, "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2).")
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(&o.all, "all", o.all, "Select all resources, including uninitialized ones, in the namespace of the specified resource types.")
cmd.Flags().StringVar(&options.resourceVersion, "resource-version", options.resourceVersion, i18n.T("If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource.")) cmd.Flags().StringVar(&o.resourceVersion, "resource-version", o.resourceVersion, i18n.T("If non-empty, the annotation update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource."))
usage := "identifying the resource to update the annotation" usage := "identifying the resource to update the annotation"
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage) cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
cmdutil.AddDryRunFlag(cmd) cmdutil.AddDryRunFlag(cmd)
cmdutil.AddInclude3rdPartyFlags(cmd) cmdutil.AddInclude3rdPartyFlags(cmd)
@ -149,9 +151,9 @@ func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command {
// Complete adapts from the command line args and factory to the data required. // Complete adapts from the command line args and factory to the data required.
func (o *AnnotateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { func (o *AnnotateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
o.RecordFlags.Complete(f.Command(cmd, false))
var err error var err error
o.RecordFlags.Complete(f.Command(cmd, false))
o.Recorder, err = o.RecordFlags.ToRecorder() o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil { if err != nil {
return err return err

View File

@ -119,17 +119,19 @@ func NewApplyOptions(out, errout io.Writer) *ApplyOptions {
GracePeriod: -1, GracePeriod: -1,
OpenApiPatch: true, OpenApiPatch: true,
Recorder: genericclioptions.NoopRecorder{},
Out: out, Out: out,
ErrOut: errout, ErrOut: errout,
} }
} }
func NewCmdApply(baseName string, f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { func NewCmdApply(baseName string, f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
options := NewApplyOptions(out, errOut) o := NewApplyOptions(out, errOut)
// Store baseName for use in printing warnings / messages involving the base command name. // Store baseName for use in printing warnings / messages involving the base command name.
// This is useful for downstream command that wrap this one. // This is useful for downstream command that wrap this one.
options.cmdBaseName = baseName o.cmdBaseName = baseName
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "apply -f FILENAME", Use: "apply -f FILENAME",
@ -139,29 +141,29 @@ func NewCmdApply(baseName string, f cmdutil.Factory, out, errOut io.Writer) *cob
Example: applyExample, Example: applyExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(validateArgs(cmd, args)) cmdutil.CheckErr(validateArgs(cmd, args))
cmdutil.CheckErr(validatePruneAll(options.Prune, options.All, options.Selector)) cmdutil.CheckErr(validatePruneAll(o.Prune, o.All, o.Selector))
cmdutil.CheckErr(options.Complete(f, cmd)) cmdutil.CheckErr(o.Complete(f, cmd))
cmdutil.CheckErr(options.Run(f, cmd)) cmdutil.CheckErr(o.Run(f, cmd))
}, },
} }
// bind flag structs // bind flag structs
options.RecordFlags.AddFlags(cmd) o.RecordFlags.AddFlags(cmd)
usage := "that contains the configuration to apply" usage := "that contains the configuration to apply"
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage) cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
cmd.MarkFlagRequired("filename") cmd.MarkFlagRequired("filename")
cmd.Flags().BoolVar(&options.Overwrite, "overwrite", options.Overwrite, "Automatically resolve conflicts between the modified and live configuration by using values from the modified configuration") cmd.Flags().BoolVar(&o.Overwrite, "overwrite", o.Overwrite, "Automatically resolve conflicts between the modified and live configuration by using values from the modified configuration")
cmd.Flags().BoolVar(&options.Prune, "prune", options.Prune, "Automatically delete resource objects, including the uninitialized ones, that do not appear in the configs and are created by either apply or create --save-config. Should be used with either -l or --all.") cmd.Flags().BoolVar(&o.Prune, "prune", o.Prune, "Automatically delete resource objects, including the uninitialized ones, that do not appear in the configs and are created by either apply or create --save-config. Should be used with either -l or --all.")
cmd.Flags().BoolVar(&options.Cascade, "cascade", options.Cascade, "Only relevant during a prune or a force apply. If true, cascade the deletion of the resources managed by pruned or deleted resources (e.g. Pods created by a ReplicationController).") cmd.Flags().BoolVar(&o.Cascade, "cascade", o.Cascade, "Only relevant during a prune or a force apply. If true, cascade the deletion of the resources managed by pruned or deleted resources (e.g. Pods created by a ReplicationController).")
cmd.Flags().IntVar(&options.GracePeriod, "grace-period", options.GracePeriod, "Only relevant during a prune or a force apply. Period of time in seconds given to pruned or deleted resources to terminate gracefully. Ignored if negative.") cmd.Flags().IntVar(&o.GracePeriod, "grace-period", o.GracePeriod, "Only relevant during a prune or a force apply. Period of time in seconds given to pruned or deleted resources to terminate gracefully. Ignored if negative.")
cmd.Flags().BoolVar(&options.Force, "force", options.Force, fmt.Sprintf("Delete and re-create the specified resource, when PATCH encounters conflict and has retried for %d times.", maxPatchRetry)) cmd.Flags().BoolVar(&o.Force, "force", o.Force, fmt.Sprintf("Delete and re-create the specified resource, when PATCH encounters conflict and has retried for %d times.", maxPatchRetry))
cmd.Flags().DurationVar(&options.Timeout, "timeout", options.Timeout, "Only relevant during a force apply. The length of time to wait before giving up on a delete of the old resource, zero means determine a timeout from the size of the object. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).") cmd.Flags().DurationVar(&o.Timeout, "timeout", o.Timeout, "Only relevant during a force apply. The length of time to wait before giving up on a delete of the old resource, zero means determine a timeout from the size of the object. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).")
cmdutil.AddValidateFlags(cmd) cmdutil.AddValidateFlags(cmd)
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)") cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
cmd.Flags().BoolVar(&options.All, "all", options.All, "Select all resources in the namespace of the specified resource types.") cmd.Flags().BoolVar(&o.All, "all", o.All, "Select all resources in the namespace of the specified resource types.")
cmd.Flags().StringArrayVar(&options.PruneWhitelist, "prune-whitelist", options.PruneWhitelist, "Overwrite the default whitelist with <group/version/kind> for --prune") cmd.Flags().StringArrayVar(&o.PruneWhitelist, "prune-whitelist", o.PruneWhitelist, "Overwrite the default whitelist with <group/version/kind> for --prune")
cmd.Flags().BoolVar(&options.OpenApiPatch, "openapi-patch", options.OpenApiPatch, "If true, use openapi to calculate diff when the openapi presents and the resource can be found in the openapi spec. Otherwise, fall back to use baked-in types.") cmd.Flags().BoolVar(&o.OpenApiPatch, "openapi-patch", o.OpenApiPatch, "If true, use openapi to calculate diff when the openapi presents and the resource can be found in the openapi spec. Otherwise, fall back to use baked-in types.")
cmdutil.AddDryRunFlag(cmd) cmdutil.AddDryRunFlag(cmd)
cmdutil.AddPrinterFlags(cmd) cmdutil.AddPrinterFlags(cmd)
cmdutil.AddInclude3rdPartyFlags(cmd) cmdutil.AddInclude3rdPartyFlags(cmd)
@ -224,9 +226,9 @@ func parsePruneResources(mapper meta.RESTMapper, gvks []string) ([]pruneResource
} }
func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
o.RecordFlags.Complete(f.Command(cmd, false))
var err error var err error
o.RecordFlags.Complete(f.Command(cmd, false))
o.Recorder, err = o.RecordFlags.ToRecorder() o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil { if err != nil {
return err return err

View File

@ -58,6 +58,7 @@ func NewAutoscaleOptions() *AutoscaleOptions {
return &AutoscaleOptions{ return &AutoscaleOptions{
FilenameOptions: resource.FilenameOptions{}, FilenameOptions: resource.FilenameOptions{},
RecordFlags: genericclioptions.NewRecordFlags(), RecordFlags: genericclioptions.NewRecordFlags(),
Recorder: genericclioptions.NoopRecorder{},
} }
} }
@ -100,9 +101,9 @@ func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command {
} }
func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
o.RecordFlags.Complete(f.Command(cmd, false))
var err error var err error
o.RecordFlags.Complete(f.Command(cmd, false))
o.Recorder, err = o.RecordFlags.ToRecorder() o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil { if err != nil {
return err return err

View File

@ -79,6 +79,8 @@ func NewCreateOptions(out, errOut io.Writer) *CreateOptions {
PrintFlags: NewPrintFlags("created"), PrintFlags: NewPrintFlags("created"),
RecordFlags: genericclioptions.NewRecordFlags(), RecordFlags: genericclioptions.NewRecordFlags(),
Recorder: genericclioptions.NoopRecorder{},
Out: out, Out: out,
ErrOut: errOut, ErrOut: errOut,
} }
@ -173,9 +175,9 @@ func (o *CreateOptions) ValidateArgs(cmd *cobra.Command, args []string) error {
} }
func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
o.RecordFlags.Complete(f.Command(cmd, false))
var err error var err error
o.RecordFlags.Complete(f.Command(cmd, false))
o.Recorder, err = o.RecordFlags.ToRecorder() o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil { if err != nil {
return err return err

View File

@ -25,6 +25,7 @@ import (
"github.com/docker/distribution/reference" "github.com/docker/distribution/reference"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -36,6 +37,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/kubectl/util/i18n" "k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/util/interrupt" "k8s.io/kubernetes/pkg/util/interrupt"
@ -93,14 +95,16 @@ type RunObject struct {
Mapping *meta.RESTMapping Mapping *meta.RESTMapping
} }
type RunOpts struct { type RunOptions struct {
PrintFlags *printers.PrintFlags PrintFlags *printers.PrintFlags
DeleteFlags *DeleteFlags DeleteFlags *DeleteFlags
DeleteOptions *DeleteOptions DeleteOptions *DeleteOptions
RecordFlags *genericclioptions.RecordFlags
DryRun bool DryRun bool
PrintObj func(runtime.Object) error PrintObj func(runtime.Object) error
Recorder genericclioptions.Recorder
ArgsLenAtDash int ArgsLenAtDash int
Attach bool Attach bool
@ -111,7 +115,6 @@ type RunOpts struct {
LeaveStdinOpen bool LeaveStdinOpen bool
Port string Port string
Quiet bool Quiet bool
Record bool
Schedule string Schedule string
TTY bool TTY bool
@ -120,15 +123,22 @@ type RunOpts struct {
ErrOut io.Writer ErrOut io.Writer
} }
func NewCmdRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command { func NewRunOptions(in io.Reader, out, errOut io.Writer) *RunOptions {
options := &RunOpts{ return &RunOptions{
PrintFlags: printers.NewPrintFlags("created"), PrintFlags: printers.NewPrintFlags("created"),
DeleteFlags: NewDeleteFlags("to use to replace the resource."), DeleteFlags: NewDeleteFlags("to use to replace the resource."),
RecordFlags: genericclioptions.NewRecordFlags(),
In: cmdIn, Recorder: genericclioptions.NoopRecorder{},
Out: cmdOut,
ErrOut: cmdErr, In: in,
Out: out,
ErrOut: errOut,
} }
}
func NewCmdRun(f cmdutil.Factory, in io.Reader, out, errOut io.Writer) *cobra.Command {
o := NewRunOptions(in, out, errOut)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "run NAME --image=image [--env=\"key=value\"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] [--command] -- [COMMAND] [args...]", Use: "run NAME --image=image [--env=\"key=value\"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] [--command] -- [COMMAND] [args...]",
@ -137,17 +147,17 @@ func NewCmdRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *co
Long: runLong, Long: runLong,
Example: runExample, Example: runExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd)) cmdutil.CheckErr(o.Complete(f, cmd))
cmdutil.CheckErr(options.Run(f, cmd, args)) cmdutil.CheckErr(o.Run(f, cmd, args))
}, },
} }
options.DeleteFlags.AddFlags(cmd) o.DeleteFlags.AddFlags(cmd)
options.PrintFlags.AddFlags(cmd) o.PrintFlags.AddFlags(cmd)
o.RecordFlags.AddFlags(cmd)
addRunFlags(cmd) addRunFlags(cmd)
cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddRecordFlag(cmd)
cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodAttachTimeout) cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodAttachTimeout)
return cmd return cmd
} }
@ -181,7 +191,15 @@ func addRunFlags(cmd *cobra.Command) {
cmd.Flags().String("schedule", "", i18n.T("A schedule in the Cron format the job should be run with.")) cmd.Flags().String("schedule", "", i18n.T("A schedule in the Cron format the job should be run with."))
} }
func (o *RunOpts) Complete(f cmdutil.Factory, cmd *cobra.Command) error { func (o *RunOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
var err error
o.RecordFlags.Complete(f.Command(cmd, false))
o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil {
return err
}
o.ArgsLenAtDash = cmd.ArgsLenAtDash() o.ArgsLenAtDash = cmd.ArgsLenAtDash()
o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run") o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
o.Expose = cmdutil.GetFlagBool(cmd, "expose") o.Expose = cmdutil.GetFlagBool(cmd, "expose")
@ -191,7 +209,6 @@ func (o *RunOpts) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
o.LeaveStdinOpen = cmdutil.GetFlagBool(cmd, "leave-stdin-open") o.LeaveStdinOpen = cmdutil.GetFlagBool(cmd, "leave-stdin-open")
o.Port = cmdutil.GetFlagString(cmd, "port") o.Port = cmdutil.GetFlagString(cmd, "port")
o.Quiet = cmdutil.GetFlagBool(cmd, "quiet") o.Quiet = cmdutil.GetFlagBool(cmd, "quiet")
o.Record = cmdutil.GetRecordFlag(cmd)
o.Schedule = cmdutil.GetFlagString(cmd, "schedule") o.Schedule = cmdutil.GetFlagString(cmd, "schedule")
o.TTY = cmdutil.GetFlagBool(cmd, "tty") o.TTY = cmdutil.GetFlagBool(cmd, "tty")
@ -223,7 +240,7 @@ func (o *RunOpts) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
return nil return nil
} }
func (o *RunOpts) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) error { func (o *RunOptions) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
// Let kubectl run follow rules for `--`, see #13004 issue // Let kubectl run follow rules for `--`, see #13004 issue
if len(args) == 0 || o.ArgsLenAtDash == 0 { if len(args) == 0 || o.ArgsLenAtDash == 0 {
return cmdutil.UsageErrorf(cmd, "NAME is required for run") return cmdutil.UsageErrorf(cmd, "NAME is required for run")
@ -432,7 +449,7 @@ func (o *RunOpts) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) erro
return utilerrors.NewAggregate(allErrs) return utilerrors.NewAggregate(allErrs)
} }
func (o *RunOpts) removeCreatedObjects(f cmdutil.Factory, createdObjects []*RunObject) error { func (o *RunOptions) removeCreatedObjects(f cmdutil.Factory, createdObjects []*RunObject) error {
for _, obj := range createdObjects { for _, obj := range createdObjects {
namespace, err := obj.Mapping.MetadataAccessor.Namespace(obj.Object) namespace, err := obj.Mapping.MetadataAccessor.Namespace(obj.Object)
if err != nil { if err != nil {
@ -571,7 +588,7 @@ func verifyImagePullPolicy(cmd *cobra.Command) error {
return cmdutil.UsageErrorf(cmd, "invalid image pull policy: %s", pullPolicy) return cmdutil.UsageErrorf(cmd, "invalid image pull policy: %s", pullPolicy)
} }
func (o *RunOpts) generateService(f cmdutil.Factory, cmd *cobra.Command, serviceGenerator string, paramsIn map[string]interface{}, namespace string) (*RunObject, error) { func (o *RunOptions) generateService(f cmdutil.Factory, cmd *cobra.Command, serviceGenerator string, paramsIn map[string]interface{}, namespace string) (*RunObject, error) {
generators := f.Generators("expose") generators := f.Generators("expose")
generator, found := generators[serviceGenerator] generator, found := generators[serviceGenerator]
if !found { if !found {
@ -617,7 +634,7 @@ func (o *RunOpts) generateService(f cmdutil.Factory, cmd *cobra.Command, service
return runObject, nil return runObject, nil
} }
func (o *RunOpts) createGeneratedObject(f cmdutil.Factory, cmd *cobra.Command, generator kubectl.Generator, names []kubectl.GeneratorParam, params map[string]interface{}, overrides, namespace string) (*RunObject, error) { func (o *RunOptions) createGeneratedObject(f cmdutil.Factory, cmd *cobra.Command, generator kubectl.Generator, names []kubectl.GeneratorParam, params map[string]interface{}, overrides, namespace string) (*RunObject, error) {
err := kubectl.ValidateParams(names, params) err := kubectl.ValidateParams(names, params)
if err != nil { if err != nil {
return nil, err return nil, err
@ -653,14 +670,8 @@ func (o *RunOpts) createGeneratedObject(f cmdutil.Factory, cmd *cobra.Command, g
return nil, err return nil, err
} }
annotations, err := mapping.MetadataAccessor.Annotations(obj) if err := o.Recorder.Record(obj); err != nil {
if err != nil { glog.V(4).Infof("error recording current command: %v", err)
return nil, err
}
if o.Record || len(annotations[kubectl.ChangeCauseAnnotation]) > 0 {
if err := cmdutil.RecordChangeCause(obj, f.Command(cmd, false)); err != nil {
return nil, err
}
} }
versioned := obj versioned := obj

View File

@ -39,6 +39,7 @@ import (
api "k8s.io/kubernetes/pkg/apis/core" api "k8s.io/kubernetes/pkg/apis/core"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/scheme" "k8s.io/kubernetes/pkg/kubectl/scheme"
"k8s.io/kubernetes/pkg/kubectl/util/i18n" "k8s.io/kubernetes/pkg/kubectl/util/i18n"
"k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/printers"
@ -205,7 +206,7 @@ func TestRunArgsFollowDashRules(t *testing.T) {
} }
deleteFlags := NewDeleteFlags("to use to replace the resource.") deleteFlags := NewDeleteFlags("to use to replace the resource.")
opts := &RunOpts{ opts := &RunOptions{
PrintFlags: printFlags, PrintFlags: printFlags,
DeleteOptions: deleteFlags.ToOptions(os.Stdout, os.Stderr), DeleteOptions: deleteFlags.ToOptions(os.Stdout, os.Stderr),
@ -219,6 +220,7 @@ func TestRunArgsFollowDashRules(t *testing.T) {
PrintObj: func(obj runtime.Object) error { PrintObj: func(obj runtime.Object) error {
return printer.PrintObj(obj, os.Stdout) return printer.PrintObj(obj, os.Stdout)
}, },
Recorder: genericclioptions.NoopRecorder{},
ArgsLenAtDash: test.argsLenAtDash, ArgsLenAtDash: test.argsLenAtDash,
} }
@ -375,7 +377,7 @@ func TestGenerateService(t *testing.T) {
deleteFlags := NewDeleteFlags("to use to replace the resource.") deleteFlags := NewDeleteFlags("to use to replace the resource.")
buff := &bytes.Buffer{} buff := &bytes.Buffer{}
opts := &RunOpts{ opts := &RunOptions{
PrintFlags: printFlags, PrintFlags: printFlags,
DeleteOptions: deleteFlags.ToOptions(os.Stdout, os.Stderr), DeleteOptions: deleteFlags.ToOptions(os.Stdout, os.Stderr),
@ -383,7 +385,7 @@ func TestGenerateService(t *testing.T) {
ErrOut: buff, ErrOut: buff,
Port: test.port, Port: test.port,
Record: false, Recorder: genericclioptions.NoopRecorder{},
PrintObj: func(obj runtime.Object) error { PrintObj: func(obj runtime.Object) error {
return printer.PrintObj(obj, buff) return printer.PrintObj(obj, buff)

View File

@ -24,9 +24,11 @@ go_library(
"//pkg/kubectl/cmd/templates:go_default_library", "//pkg/kubectl/cmd/templates:go_default_library",
"//pkg/kubectl/cmd/util:go_default_library", "//pkg/kubectl/cmd/util:go_default_library",
"//pkg/kubectl/cmd/util/env:go_default_library", "//pkg/kubectl/cmd/util/env:go_default_library",
"//pkg/kubectl/genericclioptions:go_default_library",
"//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/resource:go_default_library",
"//pkg/kubectl/util/i18n:go_default_library", "//pkg/kubectl/util/i18n:go_default_library",
"//pkg/printers:go_default_library", "//pkg/printers:go_default_library",
"//vendor/github.com/golang/glog:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/api/core/v1:go_default_library", "//vendor/k8s.io/api/core/v1:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library", "//vendor/k8s.io/apimachinery/pkg/api/errors:go_default_library",

View File

@ -22,6 +22,7 @@ import (
"k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/printers"
"github.com/golang/glog"
"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"
@ -29,16 +30,18 @@ import (
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/kubectl/util/i18n" "k8s.io/kubernetes/pkg/kubectl/util/i18n"
) )
// ImageOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of // ImageOptions 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 ImageOptions struct { type SetImageOptions struct {
resource.FilenameOptions resource.FilenameOptions
PrintFlags *printers.PrintFlags PrintFlags *printers.PrintFlags
RecordFlags *genericclioptions.RecordFlags
Infos []*resource.Info Infos []*resource.Info
Selector string Selector string
@ -46,7 +49,6 @@ type ImageOptions struct {
Err io.Writer Err io.Writer
DryRun bool DryRun bool
All bool All bool
Record bool
Output string Output string
ChangeCause string ChangeCause string
Local bool Local bool
@ -54,6 +56,7 @@ type ImageOptions struct {
ResolveImage func(in string) (string, error) ResolveImage func(in string) (string, error)
PrintObj printers.ResourcePrinterFunc PrintObj printers.ResourcePrinterFunc
Recorder genericclioptions.Recorder
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
@ -84,13 +87,20 @@ var (
kubectl set image -f path/to/file.yaml nginx=nginx:1.9.1 --local -o yaml`) kubectl set image -f path/to/file.yaml nginx=nginx:1.9.1 --local -o yaml`)
) )
func NewCmdImage(f cmdutil.Factory, out, err io.Writer) *cobra.Command { func NewImageOptions(out, errOut io.Writer) *SetImageOptions {
options := &ImageOptions{ return &SetImageOptions{
PrintFlags: printers.NewPrintFlags("image updated"), PrintFlags: printers.NewPrintFlags("image updated"),
RecordFlags: genericclioptions.NewRecordFlags(),
Recorder: genericclioptions.NoopRecorder{},
Out: out, Out: out,
Err: err, Err: errOut,
} }
}
func NewCmdImage(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
o := NewImageOptions(out, errOut)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N", Use: "image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N",
@ -99,28 +109,35 @@ func NewCmdImage(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
Long: image_long, Long: image_long,
Example: image_example, Example: image_example,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd, args)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(options.Validate()) cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(options.Run()) cmdutil.CheckErr(o.Run())
}, },
} }
options.PrintFlags.AddFlags(cmd) o.PrintFlags.AddFlags(cmd)
o.RecordFlags.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, &o.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(&o.All, "all", o.All, "Select all resources, including uninitialized ones, in the namespace of the specified resource types")
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)") cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, not including uninitialized ones, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
cmd.Flags().BoolVar(&options.Local, "local", options.Local, "If true, set image will NOT contact api-server but run locally.") cmd.Flags().BoolVar(&o.Local, "local", o.Local, "If true, set image will NOT contact api-server but run locally.")
cmdutil.AddRecordFlag(cmd)
cmdutil.AddDryRunFlag(cmd) cmdutil.AddDryRunFlag(cmd)
cmdutil.AddIncludeUninitializedFlag(cmd) cmdutil.AddIncludeUninitializedFlag(cmd)
return cmd return cmd
} }
func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { func (o *SetImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.RecordFlags.Complete(f.Command(cmd, false))
o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil {
return err
}
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
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)
o.Output = cmdutil.GetFlagString(cmd, "output") o.Output = cmdutil.GetFlagString(cmd, "output")
@ -178,7 +195,7 @@ func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
return nil return nil
} }
func (o *ImageOptions) Validate() error { func (o *SetImageOptions) Validate() error {
errors := []error{} errors := []error{}
if o.All && len(o.Selector) > 0 { if o.All && len(o.Selector) > 0 {
errors = append(errors, fmt.Errorf("cannot set --all and --selector at the same time")) errors = append(errors, fmt.Errorf("cannot set --all and --selector at the same time"))
@ -194,7 +211,7 @@ func (o *ImageOptions) Validate() error {
return utilerrors.NewAggregate(errors) return utilerrors.NewAggregate(errors)
} }
func (o *ImageOptions) Run() error { func (o *SetImageOptions) Run() error {
allErrs := []error{} allErrs := []error{}
patches := CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) { patches := CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) {
@ -236,10 +253,18 @@ func (o *ImageOptions) Run() error {
} }
return nil return nil
}) })
if transformed && err == nil { if err != nil {
return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.Object)
}
return nil, err return nil, err
}
if !transformed {
return nil, nil
}
// record this change (for rollout history)
if err := o.Recorder.Record(info.Object); err != nil {
glog.V(4).Infof("error recording current command: %v", err)
}
return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.Object)
}) })
for _, patch := range patches { for _, patch := range patches {
@ -269,17 +294,6 @@ func (o *ImageOptions) Run() error {
} }
info.Refresh(obj, true) info.Refresh(obj, true)
// record this change (for rollout history)
if o.Record || cmdutil.ContainsChangeCause(info) {
if patch, patchType, err := cmdutil.ChangeResourcePatch(info, o.ChangeCause); err == nil {
if obj, err = resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, patchType, patch); err != nil {
fmt.Fprintf(o.Err, "WARNING: changes to %s/%s can't be recorded: %v\n", info.Mapping.Resource, info.Name, err)
}
}
}
info.Refresh(obj, true)
if err := o.PrintObj(info.AsVersioned(), o.Out); err != nil { if err := o.PrintObj(info.AsVersioned(), o.Out); err != nil {
return err return err
} }

View File

@ -71,7 +71,7 @@ func TestImageLocal(t *testing.T) {
cmd.Flags().Set("output", outputFormat) cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true") cmd.Flags().Set("local", "true")
opts := ImageOptions{ opts := SetImageOptions{
PrintFlags: &printers.PrintFlags{ PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(), JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""), NamePrintFlags: printers.NewNamePrintFlags(""),
@ -105,17 +105,17 @@ func TestSetImageValidation(t *testing.T) {
testCases := []struct { testCases := []struct {
name string name string
imageOptions *ImageOptions imageOptions *SetImageOptions
expectErr string expectErr string
}{ }{
{ {
name: "test resource < 1 and filenames empty", name: "test resource < 1 and filenames empty",
imageOptions: &ImageOptions{PrintFlags: printFlags}, imageOptions: &SetImageOptions{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: &SetImageOptions{
PrintFlags: printFlags, PrintFlags: printFlags,
Resources: []string{"a", "b", "c"}, Resources: []string{"a", "b", "c"},
@ -127,7 +127,7 @@ 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: &SetImageOptions{
PrintFlags: printFlags, PrintFlags: printFlags,
Resources: []string{"a", "b", "c"}, Resources: []string{"a", "b", "c"},
FilenameOptions: resource.FilenameOptions{ FilenameOptions: resource.FilenameOptions{
@ -142,7 +142,7 @@ func TestSetImageValidation(t *testing.T) {
}, },
{ {
name: "success case", name: "success case",
imageOptions: &ImageOptions{ imageOptions: &SetImageOptions{
PrintFlags: printFlags, PrintFlags: printFlags,
Resources: []string{"a", "b", "c"}, Resources: []string{"a", "b", "c"},
FilenameOptions: resource.FilenameOptions{ FilenameOptions: resource.FilenameOptions{
@ -193,7 +193,7 @@ func TestSetMultiResourcesImageLocal(t *testing.T) {
cmd.Flags().Set("output", outputFormat) cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true") cmd.Flags().Set("local", "true")
opts := ImageOptions{ opts := SetImageOptions{
PrintFlags: &printers.PrintFlags{ PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(), JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""), NamePrintFlags: printers.NewNamePrintFlags(""),
@ -587,7 +587,7 @@ func TestSetImageRemote(t *testing.T) {
cmd := NewCmdImage(tf, out, out) cmd := NewCmdImage(tf, out, out)
cmd.SetOutput(out) cmd.SetOutput(out)
cmd.Flags().Set("output", outputFormat) cmd.Flags().Set("output", outputFormat)
opts := ImageOptions{ opts := SetImageOptions{
PrintFlags: &printers.PrintFlags{ PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(), JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""), NamePrintFlags: printers.NewNamePrintFlags(""),

View File

@ -26,12 +26,14 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/kubectl/util/i18n" "k8s.io/kubernetes/pkg/kubectl/util/i18n"
) )
@ -60,10 +62,11 @@ var (
// ResourcesOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of // ResourcesOptions 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 ResourcesOptions struct { type SetResourcesOptions struct {
resource.FilenameOptions resource.FilenameOptions
PrintFlags *printers.PrintFlags PrintFlags *printers.PrintFlags
RecordFlags *genericclioptions.RecordFlags
Infos []*resource.Info Infos []*resource.Info
Out io.Writer Out io.Writer
@ -72,7 +75,6 @@ type ResourcesOptions struct {
ContainerSelector string ContainerSelector string
Output string Output string
All bool All bool
Record bool
ChangeCause string ChangeCause string
Local bool Local bool
Cmd *cobra.Command Cmd *cobra.Command
@ -80,6 +82,7 @@ type ResourcesOptions struct {
DryRun bool DryRun bool
PrintObj printers.ResourcePrinterFunc PrintObj printers.ResourcePrinterFunc
Recorder genericclioptions.Recorder
Limits string Limits string
Requests string Requests string
@ -91,9 +94,12 @@ type ResourcesOptions struct {
// NewResourcesOptions returns a ResourcesOptions indicating all containers in the selected // NewResourcesOptions returns a ResourcesOptions indicating all containers in the selected
// 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) *SetResourcesOptions {
return &ResourcesOptions{ return &SetResourcesOptions{
PrintFlags: printers.NewPrintFlags("resource requirements updated"), PrintFlags: printers.NewPrintFlags("resource requirements updated"),
RecordFlags: genericclioptions.NewRecordFlags(),
Recorder: genericclioptions.NoopRecorder{},
Out: out, Out: out,
Err: errOut, Err: errOut,
@ -102,7 +108,7 @@ func NewResourcesOptions(out io.Writer, errOut io.Writer) *ResourcesOptions {
} }
func NewCmdResources(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command { func NewCmdResources(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.Command {
options := NewResourcesOptions(out, errOut) o := NewResourcesOptions(out, errOut)
resourceTypesWithPodTemplate := []string{} resourceTypesWithPodTemplate := []string{}
for _, resource := range f.SuggestedPodTemplateResources() { for _, resource := range f.SuggestedPodTemplateResources() {
@ -116,34 +122,41 @@ func NewCmdResources(f cmdutil.Factory, out io.Writer, errOut io.Writer) *cobra.
Long: fmt.Sprintf(resources_long, strings.Join(resourceTypesWithPodTemplate, ", ")), Long: fmt.Sprintf(resources_long, strings.Join(resourceTypesWithPodTemplate, ", ")),
Example: resources_example, Example: resources_example,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd, args)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(options.Validate()) cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(options.Run()) cmdutil.CheckErr(o.Run())
}, },
} }
options.PrintFlags.AddFlags(cmd) o.PrintFlags.AddFlags(cmd)
o.RecordFlags.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."
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage) cmdutil.AddFilenameOptionFlags(cmd, &o.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(&o.All, "all", o.All, "Select all resources, including uninitialized ones, in the namespace of the specified resource types")
cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on, not including uninitialized ones,supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)") cmd.Flags().StringVarP(&o.Selector, "selector", "l", o.Selector, "Selector (label query) to filter on, not including uninitialized ones,supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
cmd.Flags().StringVarP(&options.ContainerSelector, "containers", "c", options.ContainerSelector, "The names of containers in the selected pod templates to change, all containers are selected by default - may use wildcards") cmd.Flags().StringVarP(&o.ContainerSelector, "containers", "c", o.ContainerSelector, "The names of containers in the selected pod templates to change, all containers are selected by default - may use wildcards")
cmd.Flags().BoolVar(&options.Local, "local", options.Local, "If true, set resources will NOT contact api-server but run locally.") cmd.Flags().BoolVar(&o.Local, "local", o.Local, "If true, set resources will NOT contact api-server but run locally.")
cmdutil.AddDryRunFlag(cmd) cmdutil.AddDryRunFlag(cmd)
cmdutil.AddRecordFlag(cmd)
cmdutil.AddIncludeUninitializedFlag(cmd) cmdutil.AddIncludeUninitializedFlag(cmd)
cmd.Flags().StringVar(&options.Limits, "limits", options.Limits, "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'. Note that server side components may assign requests depending on the server configuration, such as limit ranges.") cmd.Flags().StringVar(&o.Limits, "limits", o.Limits, "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'. Note that server side components may assign requests depending on the server configuration, such as limit ranges.")
cmd.Flags().StringVar(&options.Requests, "requests", options.Requests, "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'. Note that server side components may assign requests depending on the server configuration, such as limit ranges.") cmd.Flags().StringVar(&o.Requests, "requests", o.Requests, "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'. Note that server side components may assign requests depending on the server configuration, such as limit ranges.")
return cmd return cmd
} }
func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { func (o *SetResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.RecordFlags.Complete(f.Command(cmd, false))
o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil {
return err
}
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
o.Output = cmdutil.GetFlagString(cmd, "output") o.Output = cmdutil.GetFlagString(cmd, "output")
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.DryRun = cmdutil.GetDryRunFlag(o.Cmd)
@ -194,7 +207,7 @@ func (o *ResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
return nil return nil
} }
func (o *ResourcesOptions) Validate() error { func (o *SetResourcesOptions) Validate() error {
var err error var err error
if o.All && len(o.Selector) > 0 { if o.All && len(o.Selector) > 0 {
return fmt.Errorf("cannot set --all and --selector at the same time") return fmt.Errorf("cannot set --all and --selector at the same time")
@ -211,7 +224,7 @@ func (o *ResourcesOptions) Validate() error {
return nil return nil
} }
func (o *ResourcesOptions) Run() error { func (o *SetResourcesOptions) Run() error {
allErrs := []error{} allErrs := []error{}
patches := CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) { patches := CalculatePatches(o.Infos, cmdutil.InternalVersionJSONEncoder(), func(info *resource.Info) ([]byte, error) {
transformed := false transformed := false
@ -240,10 +253,18 @@ func (o *ResourcesOptions) Run() error {
} }
return nil return nil
}) })
if transformed && err == nil { if err != nil {
return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.Object)
}
return nil, err return nil, err
}
if !transformed {
return nil, nil
}
// record this change (for rollout history)
if err := o.Recorder.Record(info.Object); err != nil {
glog.V(4).Infof("error recording current command: %v", err)
}
return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.Object)
}) })
for _, patch := range patches { for _, patch := range patches {
@ -273,16 +294,6 @@ func (o *ResourcesOptions) Run() error {
} }
info.Refresh(obj, true) info.Refresh(obj, true)
//record this change (for rollout history)
if o.Record || cmdutil.ContainsChangeCause(info) {
if err := cmdutil.RecordChangeCause(obj, o.ChangeCause); err == nil {
if obj, err = resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, false, obj); err != nil {
allErrs = append(allErrs, fmt.Errorf("changes to %s/%s can't be recorded: %v\n", info.Mapping.Resource, info.Name, err))
}
}
}
info.Refresh(obj, true)
if err := o.PrintObj(info.AsVersioned(), o.Out); err != nil { if err := o.PrintObj(info.AsVersioned(), o.Out); err != nil {
return err return err
} }

View File

@ -70,7 +70,7 @@ func TestResourcesLocal(t *testing.T) {
cmd.Flags().Set("output", outputFormat) cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true") cmd.Flags().Set("local", "true")
opts := ResourcesOptions{ opts := SetResourcesOptions{
PrintFlags: &printers.PrintFlags{ PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(), JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""), NamePrintFlags: printers.NewNamePrintFlags(""),
@ -124,7 +124,7 @@ func TestSetMultiResourcesLimitsLocal(t *testing.T) {
cmd.Flags().Set("output", outputFormat) cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true") cmd.Flags().Set("local", "true")
opts := ResourcesOptions{ opts := SetResourcesOptions{
PrintFlags: &printers.PrintFlags{ PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(), JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""), NamePrintFlags: printers.NewNamePrintFlags(""),
@ -505,7 +505,7 @@ func TestSetResourcesRemote(t *testing.T) {
cmd := NewCmdResources(tf, buf, buf) cmd := NewCmdResources(tf, buf, buf)
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("output", outputFormat) cmd.Flags().Set("output", outputFormat)
opts := ResourcesOptions{ opts := SetResourcesOptions{
PrintFlags: &printers.PrintFlags{ PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(), JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""), NamePrintFlags: printers.NewNamePrintFlags(""),

View File

@ -22,6 +22,7 @@ import (
"k8s.io/kubernetes/pkg/printers" "k8s.io/kubernetes/pkg/printers"
"github.com/golang/glog"
"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"
@ -31,16 +32,18 @@ import (
"k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/kubectl/util/i18n" "k8s.io/kubernetes/pkg/kubectl/util/i18n"
) )
// SelectorOptions is the start of the data required to perform the operation. As new fields are added, add them here instead of // SelectorOptions 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 SelectorOptions struct { type SetSelectorOptions struct {
fileOptions resource.FilenameOptions fileOptions resource.FilenameOptions
PrintFlags *printers.PrintFlags PrintFlags *printers.PrintFlags
RecordFlags *genericclioptions.RecordFlags
local bool local bool
dryrun bool dryrun bool
@ -56,6 +59,7 @@ type SelectorOptions struct {
ClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error) ClientForMapping func(mapping *meta.RESTMapping) (resource.RESTClient, error)
PrintObj printers.ResourcePrinterFunc PrintObj printers.ResourcePrinterFunc
Recorder genericclioptions.Recorder
builder *resource.Builder builder *resource.Builder
mapper meta.RESTMapper mapper meta.RESTMapper
@ -75,13 +79,20 @@ var (
kubectl create deployment my-dep -o yaml --dry-run | kubectl label --local -f - environment=qa -o yaml | kubectl create -f -`) kubectl create deployment my-dep -o yaml --dry-run | kubectl label --local -f - environment=qa -o yaml | kubectl create -f -`)
) )
// NewCmdSelector is the "set selector" command. func NewSelectorOptions(out io.Writer) *SetSelectorOptions {
func NewCmdSelector(f cmdutil.Factory, out io.Writer) *cobra.Command { return &SetSelectorOptions{
options := &SelectorOptions{
PrintFlags: printers.NewPrintFlags("selector updated"), PrintFlags: printers.NewPrintFlags("selector updated"),
RecordFlags: genericclioptions.NewRecordFlags(),
Recorder: genericclioptions.NoopRecorder{},
out: out, out: out,
} }
}
// NewCmdSelector is the "set selector" command.
func NewCmdSelector(f cmdutil.Factory, out io.Writer) *cobra.Command {
o := NewSelectorOptions(out)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "selector (-f FILENAME | TYPE NAME) EXPRESSIONS [--resource-version=version]", Use: "selector (-f FILENAME | TYPE NAME) EXPRESSIONS [--resource-version=version]",
@ -90,31 +101,38 @@ func NewCmdSelector(f cmdutil.Factory, out io.Writer) *cobra.Command {
Long: fmt.Sprintf(selectorLong, validation.LabelValueMaxLength), Long: fmt.Sprintf(selectorLong, validation.LabelValueMaxLength),
Example: selectorExample, Example: selectorExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd, args)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(options.Validate()) cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(options.RunSelector()) cmdutil.CheckErr(o.RunSelector())
}, },
} }
options.PrintFlags.AddFlags(cmd) o.PrintFlags.AddFlags(cmd)
o.RecordFlags.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.")
usage := "the resource to update the selectors" usage := "the resource to update the selectors"
cmdutil.AddFilenameOptionFlags(cmd, &options.fileOptions, usage) cmdutil.AddFilenameOptionFlags(cmd, &o.fileOptions, usage)
cmdutil.AddDryRunFlag(cmd) cmdutil.AddDryRunFlag(cmd)
cmdutil.AddRecordFlag(cmd)
cmdutil.AddIncludeUninitializedFlag(cmd) cmdutil.AddIncludeUninitializedFlag(cmd)
return cmd return cmd
} }
// Complete assigns the SelectorOptions from args. // Complete assigns the SelectorOptions from args.
func (o *SelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { func (o *SetSelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error
o.RecordFlags.Complete(f.Command(cmd, false))
o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil {
return err
}
o.local = cmdutil.GetFlagBool(cmd, "local") o.local = cmdutil.GetFlagBool(cmd, "local")
o.all = cmdutil.GetFlagBool(cmd, "all") o.all = cmdutil.GetFlagBool(cmd, "all")
o.record = cmdutil.GetRecordFlag(cmd)
o.dryrun = cmdutil.GetDryRunFlag(cmd) o.dryrun = cmdutil.GetDryRunFlag(cmd)
o.output = cmdutil.GetFlagString(cmd, "output") o.output = cmdutil.GetFlagString(cmd, "output")
@ -171,7 +189,7 @@ func (o *SelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
} }
// Validate basic inputs // Validate basic inputs
func (o *SelectorOptions) Validate() error { func (o *SetSelectorOptions) Validate() error {
if len(o.resources) < 1 && cmdutil.IsFilenameSliceEmpty(o.fileOptions.Filenames) { if len(o.resources) < 1 && cmdutil.IsFilenameSliceEmpty(o.fileOptions.Filenames) {
return fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>") return fmt.Errorf("one or more resources must be specified as <resource> <name> or <resource>/<name>")
} }
@ -182,7 +200,7 @@ func (o *SelectorOptions) Validate() error {
} }
// RunSelector executes the command. // RunSelector executes the command.
func (o *SelectorOptions) RunSelector() error { func (o *SetSelectorOptions) RunSelector() error {
r := o.builder.Do() r := o.builder.Do()
err := r.Err() err := r.Err()
if err != nil { if err != nil {
@ -195,11 +213,16 @@ func (o *SelectorOptions) RunSelector() error {
versioned := info.AsVersioned() versioned := info.AsVersioned()
patch.Info.Object = versioned patch.Info.Object = versioned
selectErr := updateSelectorForObject(info.Object, *o.selector) selectErr := updateSelectorForObject(info.Object, *o.selector)
if selectErr != nil {
if selectErr == nil {
return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.Object)
}
return nil, selectErr return nil, selectErr
}
// record this change (for rollout history)
if err := o.Recorder.Record(patch.Info.Object); err != nil {
glog.V(4).Infof("error recording current command: %v", err)
}
return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.Object)
}) })
if patch.Err != nil { if patch.Err != nil {
@ -214,14 +237,6 @@ func (o *SelectorOptions) RunSelector() error {
return err return err
} }
if o.record || cmdutil.ContainsChangeCause(info) {
if err := cmdutil.RecordChangeCause(patched, o.changeCause); err == nil {
if patched, err = resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, false, patched); err != nil {
return fmt.Errorf("changes to %s/%s can't be recorded: %v\n", info.Mapping.Resource, info.Name, err)
}
}
}
info.Refresh(patched, true) info.Refresh(patched, true)
return o.PrintObj(patch.Info.AsVersioned(), o.out) return o.PrintObj(patch.Info.AsVersioned(), o.out)
}) })

View File

@ -25,12 +25,14 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/golang/glog"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors" utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/genericclioptions"
"k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/kubectl/util/i18n" "k8s.io/kubernetes/pkg/kubectl/util/i18n"
) )
@ -55,8 +57,9 @@ var (
) )
// serviceAccountConfig encapsulates the data required to perform the operation. // serviceAccountConfig encapsulates the data required to perform the operation.
type serviceAccountConfig struct { type SetServiceAccountOptions struct {
PrintFlags *printers.PrintFlags PrintFlags *printers.PrintFlags
RecordFlags *genericclioptions.RecordFlags
fileNameOptions resource.FilenameOptions fileNameOptions resource.FilenameOptions
out io.Writer out io.Writer
@ -74,16 +77,24 @@ type serviceAccountConfig struct {
serviceAccountName string serviceAccountName string
PrintObj printers.ResourcePrinterFunc PrintObj printers.ResourcePrinterFunc
Recorder genericclioptions.Recorder
}
func NewSetServiceAccountOptions(out, errOut io.Writer) *SetServiceAccountOptions {
return &SetServiceAccountOptions{
PrintFlags: printers.NewPrintFlags("serviceaccount updated"),
RecordFlags: genericclioptions.NewRecordFlags(),
Recorder: genericclioptions.NoopRecorder{},
out: out,
err: errOut,
}
} }
// 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, errOut io.Writer) *cobra.Command {
saConfig := &serviceAccountConfig{ o := NewSetServiceAccountOptions(out, errOut)
PrintFlags: printers.NewPrintFlags("serviceaccount updated"),
out: out,
err: err,
}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "serviceaccount (-f FILENAME | TYPE NAME) SERVICE_ACCOUNT", Use: "serviceaccount (-f FILENAME | TYPE NAME) SERVICE_ACCOUNT",
@ -93,41 +104,49 @@ func NewCmdServiceAccount(f cmdutil.Factory, out, err io.Writer) *cobra.Command
Long: serviceaccountLong, Long: serviceaccountLong,
Example: serviceaccountExample, Example: serviceaccountExample,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(saConfig.Complete(f, cmd, args)) cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(saConfig.Run()) cmdutil.CheckErr(o.Run())
}, },
} }
saConfig.PrintFlags.AddFlags(cmd) o.PrintFlags.AddFlags(cmd)
o.RecordFlags.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, &o.fileNameOptions, usage)
cmd.Flags().BoolVar(&saConfig.all, "all", saConfig.all, "Select all resources, including uninitialized ones, in the namespace of the specified resource types") cmd.Flags().BoolVar(&o.all, "all", o.all, "Select all resources, including uninitialized ones, in the namespace of the specified resource types")
cmd.Flags().BoolVar(&saConfig.local, "local", saConfig.local, "If true, set serviceaccount will NOT contact api-server but run locally.") cmd.Flags().BoolVar(&o.local, "local", o.local, "If true, set serviceaccount will NOT contact api-server but run locally.")
cmdutil.AddRecordFlag(cmd)
cmdutil.AddDryRunFlag(cmd) cmdutil.AddDryRunFlag(cmd)
cmdutil.AddIncludeUninitializedFlag(cmd) cmdutil.AddIncludeUninitializedFlag(cmd)
return cmd return cmd
} }
// Complete configures serviceAccountConfig from command line args. // Complete configures serviceAccountConfig from command line args.
func (saConfig *serviceAccountConfig) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { func (o *SetServiceAccountOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
saConfig.shortOutput = cmdutil.GetFlagString(cmd, "output") == "name" var err error
saConfig.record = cmdutil.GetRecordFlag(cmd)
saConfig.changeCause = f.Command(cmd, false)
saConfig.dryRun = cmdutil.GetDryRunFlag(cmd)
saConfig.output = cmdutil.GetFlagString(cmd, "output")
saConfig.updatePodSpecForObject = f.UpdatePodSpecForObject
saConfig.cmd = cmd
if saConfig.dryRun { o.RecordFlags.Complete(f.Command(cmd, false))
saConfig.PrintFlags.Complete("%s (dry run)") o.Recorder, err = o.RecordFlags.ToRecorder()
}
printer, err := saConfig.PrintFlags.ToPrinter()
if err != nil { if err != nil {
return err return err
} }
saConfig.PrintObj = printer.PrintObj
o.shortOutput = cmdutil.GetFlagString(cmd, "output") == "name"
o.record = cmdutil.GetRecordFlag(cmd)
o.changeCause = f.Command(cmd, false)
o.dryRun = cmdutil.GetDryRunFlag(cmd)
o.output = cmdutil.GetFlagString(cmd, "output")
o.updatePodSpecForObject = f.UpdatePodSpecForObject
o.cmd = cmd
if o.dryRun {
o.PrintFlags.Complete("%s (dry run)")
}
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
return err
}
o.PrintObj = printer.PrintObj
cmdNamespace, enforceNamespace, err := f.DefaultNamespace() cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
if err != nil { if err != nil {
@ -136,22 +155,22 @@ func (saConfig *serviceAccountConfig) Complete(f cmdutil.Factory, cmd *cobra.Com
if len(args) == 0 { if len(args) == 0 {
return errors.New("serviceaccount is required") return errors.New("serviceaccount is required")
} }
saConfig.serviceAccountName = args[len(args)-1] o.serviceAccountName = args[len(args)-1]
resources := args[:len(args)-1] resources := args[:len(args)-1]
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false) includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
builder := f.NewBuilder(). builder := f.NewBuilder().
Internal(). Internal().
LocalParam(saConfig.local). LocalParam(o.local).
ContinueOnError(). ContinueOnError().
NamespaceParam(cmdNamespace).DefaultNamespace(). NamespaceParam(cmdNamespace).DefaultNamespace().
FilenameParam(enforceNamespace, &saConfig.fileNameOptions). FilenameParam(enforceNamespace, &o.fileNameOptions).
IncludeUninitialized(includeUninitialized). IncludeUninitialized(includeUninitialized).
Flatten() Flatten()
if !saConfig.local { if !o.local {
builder.ResourceTypeOrNameArgs(saConfig.all, resources...). builder.ResourceTypeOrNameArgs(o.all, resources...).
Latest() Latest()
} }
saConfig.infos, err = builder.Do().Infos() o.infos, err = builder.Do().Infos()
if err != nil { if err != nil {
return err return err
} }
@ -159,26 +178,34 @@ func (saConfig *serviceAccountConfig) Complete(f cmdutil.Factory, cmd *cobra.Com
} }
// Run creates and applies the patch either locally or calling apiserver. // Run creates and applies the patch either locally or calling apiserver.
func (saConfig *serviceAccountConfig) Run() error { func (o *SetServiceAccountOptions) Run() error {
patchErrs := []error{} patchErrs := []error{}
patchFn := func(info *resource.Info) ([]byte, error) { patchFn := func(info *resource.Info) ([]byte, error) {
info.Object = info.AsVersioned() info.Object = info.AsVersioned()
saConfig.updatePodSpecForObject(info.Object, func(podSpec *v1.PodSpec) error { _, err := o.updatePodSpecForObject(info.Object, func(podSpec *v1.PodSpec) error {
podSpec.ServiceAccountName = saConfig.serviceAccountName podSpec.ServiceAccountName = o.serviceAccountName
return nil return nil
}) })
if err != nil {
return nil, err
}
// record this change (for rollout history)
if err := o.Recorder.Record(info.Object); err != nil {
glog.V(4).Infof("error recording current command: %v", err)
}
return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.Object) return runtime.Encode(cmdutil.InternalVersionJSONEncoder(), info.Object)
} }
patches := CalculatePatches(saConfig.infos, cmdutil.InternalVersionJSONEncoder(), patchFn) patches := CalculatePatches(o.infos, cmdutil.InternalVersionJSONEncoder(), patchFn)
for _, patch := range patches { for _, patch := range patches {
info := patch.Info info := patch.Info
if patch.Err != nil { if patch.Err != nil {
patchErrs = append(patchErrs, fmt.Errorf("error: %s/%s %v\n", info.Mapping.Resource, info.Name, patch.Err)) patchErrs = append(patchErrs, fmt.Errorf("error: %s/%s %v\n", info.Mapping.Resource, info.Name, patch.Err))
continue continue
} }
if saConfig.local || saConfig.dryRun { if o.local || o.dryRun {
if err := saConfig.PrintObj(patch.Info.AsVersioned(), saConfig.out); err != nil { if err := o.PrintObj(patch.Info.AsVersioned(), o.out); err != nil {
return err return err
} }
continue continue
@ -189,15 +216,8 @@ func (saConfig *serviceAccountConfig) Run() error {
continue continue
} }
info.Refresh(patched, true) info.Refresh(patched, true)
if saConfig.record || cmdutil.ContainsChangeCause(info) {
if patch, patchType, err := cmdutil.ChangeResourcePatch(info, saConfig.changeCause); err == nil {
if patched, err = resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, patchType, patch); err != nil {
fmt.Fprintf(saConfig.err, "WARNING: changes to %s/%s can't be recorded: %v\n", info.Mapping.Resource, info.Name, err)
}
}
}
if err := saConfig.PrintObj(info.AsVersioned(), saConfig.out); err != nil { if err := o.PrintObj(info.AsVersioned(), o.out); err != nil {
return err return err
} }
} }

View File

@ -89,7 +89,7 @@ func TestSetServiceAccountLocal(t *testing.T) {
cmd.Flags().Set("output", outputFormat) 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{ saConfig := SetServiceAccountOptions{
PrintFlags: &printers.PrintFlags{ PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(), JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""), NamePrintFlags: printers.NewNamePrintFlags(""),
@ -133,7 +133,7 @@ func TestSetServiceAccountMultiLocal(t *testing.T) {
cmd.SetOutput(buf) cmd.SetOutput(buf)
cmd.Flags().Set("output", outputFormat) cmd.Flags().Set("output", outputFormat)
cmd.Flags().Set("local", "true") cmd.Flags().Set("local", "true")
opts := serviceAccountConfig{ opts := SetServiceAccountOptions{
PrintFlags: &printers.PrintFlags{ PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(), JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""), NamePrintFlags: printers.NewNamePrintFlags(""),
@ -377,7 +377,7 @@ func TestSetServiceAccountRemote(t *testing.T) {
cmd := NewCmdServiceAccount(tf, out, out) cmd := NewCmdServiceAccount(tf, out, out)
cmd.SetOutput(out) cmd.SetOutput(out)
cmd.Flags().Set("output", outputFormat) cmd.Flags().Set("output", outputFormat)
saConfig := serviceAccountConfig{ saConfig := SetServiceAccountOptions{
PrintFlags: &printers.PrintFlags{ PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(), JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""), NamePrintFlags: printers.NewNamePrintFlags(""),
@ -424,7 +424,7 @@ func TestServiceAccountValidation(t *testing.T) {
cmd := NewCmdServiceAccount(tf, out, out) cmd := NewCmdServiceAccount(tf, out, out)
cmd.SetOutput(out) cmd.SetOutput(out)
saConfig := &serviceAccountConfig{ saConfig := &SetServiceAccountOptions{
PrintFlags: &printers.PrintFlags{ PrintFlags: &printers.PrintFlags{
JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(), JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(),
NamePrintFlags: printers.NewNamePrintFlags(""), NamePrintFlags: printers.NewNamePrintFlags(""),

View File

@ -91,6 +91,8 @@ func NewEditOptions(editMode EditMode, out, errOut io.Writer) *EditOptions {
Output: "yaml", Output: "yaml",
WindowsLineEndings: goruntime.GOOS == "windows", WindowsLineEndings: goruntime.GOOS == "windows",
Recorder: genericclioptions.NoopRecorder{},
Out: out, Out: out,
ErrOut: errOut, ErrOut: errOut,
} }
@ -104,9 +106,9 @@ type editPrinterOptions struct {
// Complete completes all the required options // Complete completes all the required options
func (o *EditOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Command) error { func (o *EditOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Command) error {
o.RecordFlags.Complete(f.Command(cmd, false))
var err error var err error
o.RecordFlags.Complete(f.Command(cmd, false))
o.Recorder, err = o.RecordFlags.ToRecorder() o.Recorder, err = o.RecordFlags.ToRecorder()
if err != nil { if err != nil {
return err return err

View File

@ -521,10 +521,6 @@ func AddRecordFlag(cmd *cobra.Command) {
cmd.Flags().Bool("record", false, "Record current kubectl command in the resource annotation. If set to false, do not record the command. If set to true, record the command. If not set, default to updating the existing annotation value only if one already exists.") cmd.Flags().Bool("record", false, "Record current kubectl command in the resource annotation. If set to false, do not record the command. If set to true, record the command. If not set, default to updating the existing annotation value only if one already exists.")
} }
func AddRecordVarFlag(cmd *cobra.Command, record *bool) {
cmd.Flags().BoolVar(record, "record", *record, "Record current kubectl command in the resource annotation. If set to false, do not record the command. If set to true, record the command. If not set, default to updating the existing annotation value only if one already exists.")
}
func GetRecordFlag(cmd *cobra.Command) bool { func GetRecordFlag(cmd *cobra.Command) bool {
return GetFlagBool(cmd, "record") return GetFlagBool(cmd, "record")
} }

View File

@ -38,7 +38,7 @@ type RecordFlags struct {
// explicitly given by the user // explicitly given by the user
func (f *RecordFlags) ToRecorder() (Recorder, error) { func (f *RecordFlags) ToRecorder() (Recorder, error) {
if f == nil { if f == nil {
return &NoopRecorder{}, nil return NoopRecorder{}, nil
} }
shouldRecord := false shouldRecord := false
@ -49,7 +49,7 @@ func (f *RecordFlags) ToRecorder() (Recorder, error) {
// if flag was explicitly set to false by the user, // if flag was explicitly set to false by the user,
// do not record // do not record
if !shouldRecord { if !shouldRecord {
return &NoopRecorder{}, nil return NoopRecorder{}, nil
} }
return &ChangeCauseRecorder{ return &ChangeCauseRecorder{
@ -98,7 +98,7 @@ type Recorder interface {
type NoopRecorder struct{} type NoopRecorder struct{}
// Record implements Recorder // Record implements Recorder
func (r *NoopRecorder) Record(obj runtime.Object) error { func (r NoopRecorder) Record(obj runtime.Object) error {
return nil return nil
} }