From e2a5c39b23c9559024b47488b32d4a5a56b8ff5d Mon Sep 17 00:00:00 2001 From: David Eads Date: Wed, 18 Apr 2018 11:20:33 -0400 Subject: [PATCH] use record flags --- pkg/kubectl/BUILD | 1 + pkg/kubectl/cmd/BUILD | 2 +- pkg/kubectl/cmd/annotate.go | 53 +++++++----- pkg/kubectl/cmd/annotate_test.go | 22 ++--- pkg/kubectl/cmd/apply.go | 7 +- pkg/kubectl/cmd/apply_edit_last_applied.go | 23 +++-- pkg/kubectl/cmd/apply_set_last_applied.go | 22 +++-- pkg/kubectl/cmd/autoscale.go | 52 +++++++++--- pkg/kubectl/cmd/create/BUILD | 2 + pkg/kubectl/cmd/create/create.go | 85 +++++++++++-------- pkg/kubectl/cmd/edit.go | 36 ++++---- .../edit/testcase-list-record/3.request | 5 -- .../edit/testcase-list-record/4.request | 3 - pkg/kubectl/cmd/util/editor/BUILD | 1 + pkg/kubectl/cmd/util/editor/editoptions.go | 39 ++++++--- pkg/kubectl/genericclioptions/BUILD | 30 +++++++ 16 files changed, 244 insertions(+), 139 deletions(-) create mode 100644 pkg/kubectl/genericclioptions/BUILD diff --git a/pkg/kubectl/BUILD b/pkg/kubectl/BUILD index 8f15c9189c..f4de498d53 100644 --- a/pkg/kubectl/BUILD +++ b/pkg/kubectl/BUILD @@ -206,6 +206,7 @@ filegroup( "//pkg/kubectl/categories:all-srcs", "//pkg/kubectl/cmd:all-srcs", "//pkg/kubectl/explain:all-srcs", + "//pkg/kubectl/genericclioptions:all-srcs", "//pkg/kubectl/metricsutil:all-srcs", "//pkg/kubectl/plugins:all-srcs", "//pkg/kubectl/proxy:all-srcs", diff --git a/pkg/kubectl/cmd/BUILD b/pkg/kubectl/cmd/BUILD index 7593278af5..c14bf11de3 100644 --- a/pkg/kubectl/cmd/BUILD +++ b/pkg/kubectl/cmd/BUILD @@ -41,7 +41,6 @@ go_library( "plugin.go", "portforward.go", "proxy.go", - "record_flags.go", "replace.go", "rollingupdate.go", "run.go", @@ -79,6 +78,7 @@ go_library( "//pkg/kubectl/cmd/util/editor:go_default_library", "//pkg/kubectl/cmd/util/openapi:go_default_library", "//pkg/kubectl/explain:go_default_library", + "//pkg/kubectl/genericclioptions:go_default_library", "//pkg/kubectl/metricsutil:go_default_library", "//pkg/kubectl/plugins:go_default_library", "//pkg/kubectl/proxy:go_default_library", diff --git a/pkg/kubectl/cmd/annotate.go b/pkg/kubectl/cmd/annotate.go index fcd04f2671..8e4adaefd7 100644 --- a/pkg/kubectl/cmd/annotate.go +++ b/pkg/kubectl/cmd/annotate.go @@ -34,6 +34,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/util/i18n" ) @@ -42,21 +43,22 @@ import ( type AnnotateOptions struct { // Filename options resource.FilenameOptions + RecordFlags *genericclioptions.RecordFlags // Common user flags - overwrite bool - local bool - dryrun bool - all bool - resourceVersion string - selector string - outputFormat string - recordChangeCause bool + overwrite bool + local bool + dryrun bool + all bool + resourceVersion string + selector string + outputFormat string // results of arg parsing resources []string newAnnotations map[string]string removeAnnotations []string + Recorder genericclioptions.Recorder // Common share fields out io.Writer @@ -97,8 +99,15 @@ var ( kubectl annotate pods foo description-`)) ) +func NewAnnotateOptions(out io.Writer) *AnnotateOptions { + return &AnnotateOptions{ + out: out, + RecordFlags: genericclioptions.NewRecordFlags(), + } +} + func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command { - options := &AnnotateOptions{} + options := NewAnnotateOptions(out) validArgs := cmdutil.ValidArgList(f) cmd := &cobra.Command{ @@ -108,7 +117,7 @@ func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command { Long: annotateLong + "\n\n" + cmdutil.ValidResourceTypeList(f), Example: annotateExample, Run: func(cmd *cobra.Command, args []string) { - if err := options.Complete(out, cmd, args); err != nil { + if err := options.Complete(f, cmd, args); err != nil { cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, "%v", err)) } if err := options.Validate(); err != nil { @@ -119,6 +128,10 @@ func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command { ValidArgs: validArgs, ArgAliases: kubectl.ResourceAliases(validArgs), } + + // bind flag structs + options.RecordFlags.AddFlags(cmd) + cmdutil.AddPrinterFlags(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.") @@ -129,18 +142,23 @@ func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command { usage := "identifying the resource to update the annotation" cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage) cmdutil.AddDryRunFlag(cmd) - cmdutil.AddRecordFlag(cmd) cmdutil.AddInclude3rdPartyFlags(cmd) return cmd } // Complete adapts from the command line args and factory to the data required. -func (o *AnnotateOptions) Complete(out io.Writer, cmd *cobra.Command, args []string) (err error) { - o.out = out +func (o *AnnotateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + o.RecordFlags.Complete(f.Command(cmd, false)) + + var err error + o.Recorder, err = o.RecordFlags.ToRecorder() + if err != nil { + return err + } + o.outputFormat = cmdutil.GetFlagString(cmd, "output") o.dryrun = cmdutil.GetDryRunFlag(cmd) - o.recordChangeCause = cmdutil.GetRecordFlag(cmd) // retrieves resource and annotation args from args // also checks args to verify that all resources are specified before annotations @@ -174,8 +192,6 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro return err } - changeCause := f.Command(cmd, false) - includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false) b := f.NewBuilder(). Unstructured(). @@ -232,9 +248,8 @@ func (o AnnotateOptions) RunAnnotate(f cmdutil.Factory, cmd *cobra.Command) erro if err != nil { return err } - // If we should record change-cause, add it to new annotations - if cmdutil.ContainsChangeCause(info) || o.recordChangeCause { - o.newAnnotations[kubectl.ChangeCauseAnnotation] = changeCause + if err := o.Recorder.Record(info.Object); err != nil { + glog.V(4).Infof("error recording current command: %v", err) } if err := o.updateAnnotations(obj); err != nil { return err diff --git a/pkg/kubectl/cmd/annotate_test.go b/pkg/kubectl/cmd/annotate_test.go index 409070e26c..7eedc2188f 100644 --- a/pkg/kubectl/cmd/annotate_test.go +++ b/pkg/kubectl/cmd/annotate_test.go @@ -431,8 +431,8 @@ func TestAnnotateErrors(t *testing.T) { for k, v := range testCase.flags { cmd.Flags().Set(k, v) } - options := &AnnotateOptions{} - err := options.Complete(buf, cmd, testCase.args) + options := NewAnnotateOptions(buf) + err := options.Complete(tf, cmd, testCase.args) if err == nil { err = options.Validate() } @@ -488,9 +488,9 @@ func TestAnnotateObject(t *testing.T) { buf := bytes.NewBuffer([]byte{}) cmd := NewCmdAnnotate(tf, buf) cmd.SetOutput(buf) - options := &AnnotateOptions{} + options := NewAnnotateOptions(buf) args := []string{"pods/foo", "a=b", "c-"} - if err := options.Complete(buf, cmd, args); err != nil { + if err := options.Complete(tf, cmd, args); err != nil { t.Fatalf("unexpected error: %v", err) } if err := options.Validate(); err != nil { @@ -542,10 +542,10 @@ func TestAnnotateObjectFromFile(t *testing.T) { buf := bytes.NewBuffer([]byte{}) cmd := NewCmdAnnotate(tf, buf) cmd.SetOutput(buf) - options := &AnnotateOptions{} + options := NewAnnotateOptions(buf) options.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"} args := []string{"a=b", "c-"} - if err := options.Complete(buf, cmd, args); err != nil { + if err := options.Complete(tf, cmd, args); err != nil { t.Fatalf("unexpected error: %v", err) } if err := options.Validate(); err != nil { @@ -573,10 +573,11 @@ func TestAnnotateLocal(t *testing.T) { buf := bytes.NewBuffer([]byte{}) cmd := NewCmdAnnotate(tf, buf) - options := &AnnotateOptions{local: true} + options := NewAnnotateOptions(buf) + options.local = true options.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"} args := []string{"a=b"} - if err := options.Complete(buf, cmd, args); err != nil { + if err := options.Complete(tf, cmd, args); err != nil { t.Fatalf("unexpected error: %v", err) } if err := options.Validate(); err != nil { @@ -629,9 +630,10 @@ func TestAnnotateMultipleObjects(t *testing.T) { buf := bytes.NewBuffer([]byte{}) cmd := NewCmdAnnotate(tf, buf) cmd.SetOutput(buf) - options := &AnnotateOptions{all: true} + options := NewAnnotateOptions(buf) + options.all = true args := []string{"pods", "a=b", "c-"} - if err := options.Complete(buf, cmd, args); err != nil { + if err := options.Complete(tf, cmd, args); err != nil { t.Fatalf("unexpected error: %v", err) } if err := options.Validate(); err != nil { diff --git a/pkg/kubectl/cmd/apply.go b/pkg/kubectl/cmd/apply.go index 694c3ff917..f38179c664 100644 --- a/pkg/kubectl/cmd/apply.go +++ b/pkg/kubectl/cmd/apply.go @@ -45,16 +45,17 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/scheme" "k8s.io/kubernetes/pkg/kubectl/util/i18n" ) type ApplyOptions struct { - RecordFlags *RecordFlags + RecordFlags *genericclioptions.RecordFlags FilenameOptions resource.FilenameOptions - Recorder Recorder + Recorder genericclioptions.Recorder Selector string Force bool @@ -111,7 +112,7 @@ var ( func NewApplyOptions(out, errout io.Writer) *ApplyOptions { return &ApplyOptions{ - RecordFlags: NewRecordFlags(), + RecordFlags: genericclioptions.NewRecordFlags(), Overwrite: true, Cascade: true, diff --git a/pkg/kubectl/cmd/apply_edit_last_applied.go b/pkg/kubectl/cmd/apply_edit_last_applied.go index 6d97a551fa..9a2319ee74 100644 --- a/pkg/kubectl/cmd/apply_edit_last_applied.go +++ b/pkg/kubectl/cmd/apply_edit_last_applied.go @@ -18,7 +18,6 @@ package cmd import ( "io" - "runtime" "github.com/spf13/cobra" @@ -59,11 +58,8 @@ var ( ) func NewCmdApplyEditLastApplied(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { - options := &editor.EditOptions{ - EditMode: editor.ApplyEditMode, - Output: "yaml", - WindowsLineEndings: runtime.GOOS == "windows", - } + o := editor.NewEditOptions(editor.ApplyEditMode, out, errOut) + validArgs := cmdutil.ValidArgList(f) cmd := &cobra.Command{ @@ -73,11 +69,10 @@ func NewCmdApplyEditLastApplied(f cmdutil.Factory, out, errOut io.Writer) *cobra Long: applyEditLastAppliedLong, Example: applyEditLastAppliedExample, Run: func(cmd *cobra.Command, args []string) { - options.ChangeCause = f.Command(cmd, false) - if err := options.Complete(f, out, errOut, args, cmd); err != nil { + if err := o.Complete(f, args, cmd); err != nil { cmdutil.CheckErr(err) } - if err := options.Run(); err != nil { + if err := o.Run(); err != nil { cmdutil.CheckErr(err) } }, @@ -85,12 +80,14 @@ func NewCmdApplyEditLastApplied(f cmdutil.Factory, out, errOut io.Writer) *cobra ArgAliases: kubectl.ResourceAliases(validArgs), } + // bind flag structs + o.RecordFlags.AddFlags(cmd) + usage := "to use to edit the resource" - cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage) - cmd.Flags().StringVarP(&options.Output, "output", "o", options.Output, "Output format. One of: yaml|json.") - cmd.Flags().BoolVar(&options.WindowsLineEndings, "windows-line-endings", options.WindowsLineEndings, + cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage) + cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "Output format. One of: yaml|json.") + cmd.Flags().BoolVar(&o.WindowsLineEndings, "windows-line-endings", o.WindowsLineEndings, "Defaults to the line ending native to your platform.") - cmdutil.AddRecordVarFlag(cmd, &options.Record) cmdutil.AddIncludeUninitializedFlag(cmd) return cmd diff --git a/pkg/kubectl/cmd/apply_set_last_applied.go b/pkg/kubectl/cmd/apply_set_last_applied.go index accfea60eb..fb74479640 100644 --- a/pkg/kubectl/cmd/apply_set_last_applied.go +++ b/pkg/kubectl/cmd/apply_set_last_applied.go @@ -54,8 +54,9 @@ type SetLastAppliedOptions struct { Output string PatchBufferList []PatchBuffer Factory cmdutil.Factory - Out io.Writer - ErrOut io.Writer + + Out io.Writer + ErrOut io.Writer } type PatchBuffer struct { @@ -81,8 +82,15 @@ var ( `)) ) -func NewCmdApplySetLastApplied(f cmdutil.Factory, out, err io.Writer) *cobra.Command { - options := &SetLastAppliedOptions{Out: out, ErrOut: err} +func NewSetLastAppliedOptions(out, errout io.Writer) *SetLastAppliedOptions { + return &SetLastAppliedOptions{ + Out: out, + ErrOut: errout, + } +} + +func NewCmdApplySetLastApplied(f cmdutil.Factory, out, errout io.Writer) *cobra.Command { + options := NewSetLastAppliedOptions(out, errout) cmd := &cobra.Command{ Use: "set-last-applied -f FILENAME", DisableFlagsInUseLine: true, @@ -97,7 +105,6 @@ func NewCmdApplySetLastApplied(f cmdutil.Factory, out, err io.Writer) *cobra.Com } cmdutil.AddDryRunFlag(cmd) - cmdutil.AddRecordFlag(cmd) cmdutil.AddPrinterFlags(cmd) cmd.Flags().BoolVar(&options.CreateAnnotation, "create-annotation", options.CreateAnnotation, "Will create 'last-applied-configuration' annotations if current objects doesn't have one") usage := "that contains the last-applied-configuration annotations" @@ -111,12 +118,9 @@ func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) o.Output = cmdutil.GetFlagString(cmd, "output") o.ShortOutput = o.Output == "name" - var err error o.Mapper, o.Typer = f.Object() - if err != nil { - return err - } + var err error o.Namespace, o.EnforceNamespace, err = f.DefaultNamespace() return err } diff --git a/pkg/kubectl/cmd/autoscale.go b/pkg/kubectl/cmd/autoscale.go index 434849fa0d..344fc8d89e 100644 --- a/pkg/kubectl/cmd/autoscale.go +++ b/pkg/kubectl/cmd/autoscale.go @@ -24,9 +24,11 @@ import ( "k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/util/i18n" + "github.com/golang/glog" "github.com/spf13/cobra" ) @@ -45,8 +47,22 @@ var ( kubectl autoscale rc foo --max=5 --cpu-percent=80`)) ) +type AutoscaleOptions struct { + FilenameOptions resource.FilenameOptions + RecordFlags *genericclioptions.RecordFlags + + Recorder genericclioptions.Recorder +} + +func NewAutoscaleOptions() *AutoscaleOptions { + return &AutoscaleOptions{ + FilenameOptions: resource.FilenameOptions{}, + RecordFlags: genericclioptions.NewRecordFlags(), + } +} + func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command { - options := &resource.FilenameOptions{} + o := NewAutoscaleOptions() validArgs := []string{"deployment", "replicaset", "replicationcontroller"} argAliases := kubectl.ResourceAliases(validArgs) @@ -58,12 +74,16 @@ func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command { Long: autoscaleLong, Example: autoscaleExample, Run: func(cmd *cobra.Command, args []string) { - err := RunAutoscale(f, out, cmd, args, options) - cmdutil.CheckErr(err) + cmdutil.CheckErr(o.Complete(f, cmd)) + cmdutil.CheckErr(o.RunAutoscale(f, out, cmd, args)) }, ValidArgs: validArgs, ArgAliases: argAliases, } + + // bind flag structs + o.RecordFlags.AddFlags(cmd) + cmdutil.AddPrinterFlags(cmd) cmd.Flags().String("generator", cmdutil.HorizontalPodAutoscalerV1GeneratorName, i18n.T("The name of the API generator to use. Currently there is only 1 generator.")) cmd.Flags().Int32("min", -1, "The lower limit for the number of pods that can be set by the autoscaler. If it's not specified or negative, the server will apply a default value.") @@ -73,14 +93,25 @@ func NewCmdAutoscale(f cmdutil.Factory, out io.Writer) *cobra.Command { cmd.Flags().String("name", "", i18n.T("The name for the newly created object. If not specified, the name of the input resource will be used.")) cmdutil.AddDryRunFlag(cmd) usage := "identifying the resource to autoscale." - cmdutil.AddFilenameOptionFlags(cmd, options, usage) + cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage) cmdutil.AddApplyAnnotationFlags(cmd) - cmdutil.AddRecordFlag(cmd) cmdutil.AddInclude3rdPartyFlags(cmd) return cmd } -func RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions) error { +func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { + o.RecordFlags.Complete(f.Command(cmd, false)) + + var err error + o.Recorder, err = o.RecordFlags.ToRecorder() + if err != nil { + return err + } + + return nil +} + +func (o *AutoscaleOptions) RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error { namespace, enforceNamespace, err := f.DefaultNamespace() if err != nil { return err @@ -95,7 +126,7 @@ func RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s Internal(). ContinueOnError(). NamespaceParam(namespace).DefaultNamespace(). - FilenameParam(enforceNamespace, options). + FilenameParam(enforceNamespace, &o.FilenameOptions). ResourceTypeOrNameArgs(false, args...). Flatten(). Do() @@ -149,11 +180,8 @@ func RunAutoscale(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []s if err != nil { return err } - if cmdutil.ShouldRecord(cmd, hpa) { - if err := cmdutil.RecordChangeCause(hpa.Object, f.Command(cmd, false)); err != nil { - return err - } - object = hpa.Object + if err := o.Recorder.Record(hpa.Object); err != nil { + glog.V(4).Infof("error recording current command: %v", err) } if cmdutil.GetDryRunFlag(cmd) { return cmdutil.PrintObject(cmd, object, out) diff --git a/pkg/kubectl/cmd/create/BUILD b/pkg/kubectl/cmd/create/BUILD index a10104449a..877344edf5 100644 --- a/pkg/kubectl/cmd/create/BUILD +++ b/pkg/kubectl/cmd/create/BUILD @@ -27,9 +27,11 @@ go_library( "//pkg/kubectl/cmd/templates:go_default_library", "//pkg/kubectl/cmd/util:go_default_library", "//pkg/kubectl/cmd/util/editor:go_default_library", + "//pkg/kubectl/genericclioptions:go_default_library", "//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/util/i18n: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/k8s.io/api/batch/v1:go_default_library", "//vendor/k8s.io/api/batch/v1beta1:go_default_library", diff --git a/pkg/kubectl/cmd/create/create.go b/pkg/kubectl/cmd/create/create.go index 66bf40555d..b696096931 100644 --- a/pkg/kubectl/cmd/create/create.go +++ b/pkg/kubectl/cmd/create/create.go @@ -27,6 +27,7 @@ import ( "net/url" + "github.com/golang/glog" "k8s.io/apimachinery/pkg/api/meta" kruntime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -34,13 +35,14 @@ import ( "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/cmd/util/editor" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/resource" "k8s.io/kubernetes/pkg/kubectl/util/i18n" ) type CreateOptions struct { - PrintFlags *PrintFlags - PrintObj func(obj kruntime.Object) error + PrintFlags *PrintFlags + RecordFlags *genericclioptions.RecordFlags DryRun bool @@ -50,6 +52,9 @@ type CreateOptions struct { Raw string Out io.Writer ErrOut io.Writer + + Recorder genericclioptions.Recorder + PrintObj func(obj kruntime.Object) error } var ( @@ -69,13 +74,18 @@ var ( kubectl create -f docker-registry.yaml --edit -o json`)) ) -func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { - options := &CreateOptions{ - PrintFlags: NewPrintFlags("created"), +func NewCreateOptions(out, errOut io.Writer) *CreateOptions { + return &CreateOptions{ + PrintFlags: NewPrintFlags("created"), + RecordFlags: genericclioptions.NewRecordFlags(), Out: out, ErrOut: errOut, } +} + +func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { + o := NewCreateOptions(out, errOut) cmd := &cobra.Command{ Use: "create -f FILENAME", @@ -84,32 +94,34 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { Long: createLong, Example: createExample, Run: func(cmd *cobra.Command, args []string) { - if cmdutil.IsFilenameSliceEmpty(options.FilenameOptions.Filenames) { + if cmdutil.IsFilenameSliceEmpty(o.FilenameOptions.Filenames) { defaultRunFunc := cmdutil.DefaultSubCommandRun(errOut) defaultRunFunc(cmd, args) return } - cmdutil.CheckErr(options.Complete(cmd)) - cmdutil.CheckErr(options.ValidateArgs(cmd, args)) - cmdutil.CheckErr(options.RunCreate(f, cmd)) + cmdutil.CheckErr(o.Complete(f, cmd)) + cmdutil.CheckErr(o.ValidateArgs(cmd, args)) + cmdutil.CheckErr(o.RunCreate(f, cmd)) }, } + // bind flag structs + o.RecordFlags.AddFlags(cmd) + usage := "to use to create the resource" - cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage) + cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage) cmd.MarkFlagRequired("filename") cmdutil.AddValidateFlags(cmd) - cmd.Flags().BoolVar(&options.EditBeforeCreate, "edit", options.EditBeforeCreate, "Edit the API resource before creating") + cmd.Flags().BoolVar(&o.EditBeforeCreate, "edit", o.EditBeforeCreate, "Edit the API resource before creating") cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows", "Only relevant if --edit=true. Defaults to the line ending native to your platform.") cmdutil.AddApplyAnnotationFlags(cmd) - cmdutil.AddRecordFlag(cmd) cmdutil.AddDryRunFlag(cmd) cmdutil.AddInclude3rdPartyFlags(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().StringVar(&options.Raw, "raw", options.Raw, "Raw URI to POST to the server. Uses the transport specified by the kubeconfig file.") + 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().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to POST to the server. Uses the transport specified by the kubeconfig file.") - options.PrintFlags.AddFlags(cmd) + o.PrintFlags.AddFlags(cmd) // create subcommands cmd.AddCommand(NewCmdCreateNamespace(f, out)) @@ -160,7 +172,15 @@ func (o *CreateOptions) ValidateArgs(cmd *cobra.Command, args []string) error { return nil } -func (o *CreateOptions) Complete(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 + o.Recorder, err = o.RecordFlags.ToRecorder() + if err != nil { + return err + } + o.DryRun = cmdutil.GetDryRunFlag(cmd) if o.DryRun { @@ -186,7 +206,7 @@ func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error { } if o.EditBeforeCreate { - return RunEditOnCreate(f, o.Out, o.ErrOut, cmd, &o.FilenameOptions) + return RunEditOnCreate(f, o.RecordFlags, o.Out, o.ErrOut, cmd, &o.FilenameOptions) } schema, err := f.Validator(cmdutil.GetFlagBool(cmd, "validate")) if err != nil { @@ -221,10 +241,8 @@ func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error { return cmdutil.AddSourceToErr("creating", info.Source, err) } - if cmdutil.ShouldRecord(cmd, info) { - if err := cmdutil.RecordChangeCause(info.Object, f.Command(cmd, false)); err != nil { - return cmdutil.AddSourceToErr("creating", info.Source, err) - } + if err := o.Recorder.Record(info.Object); err != nil { + glog.V(4).Infof("error recording current command: %v", err) } if !o.DryRun { @@ -273,21 +291,18 @@ func (o *CreateOptions) raw(f cmdutil.Factory) error { return nil } -func RunEditOnCreate(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, options *resource.FilenameOptions) error { - editOptions := &editor.EditOptions{ - EditMode: editor.EditBeforeCreateMode, - FilenameOptions: *options, - ValidateOptions: cmdutil.ValidateOptions{ - EnableValidation: cmdutil.GetFlagBool(cmd, "validate"), - }, - Output: cmdutil.GetFlagString(cmd, "output"), - WindowsLineEndings: cmdutil.GetFlagBool(cmd, "windows-line-endings"), - ApplyAnnotation: cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), - Record: cmdutil.GetFlagBool(cmd, "record"), - ChangeCause: f.Command(cmd, false), - Include3rdParty: cmdutil.GetFlagBool(cmd, "include-extended-apis"), +func RunEditOnCreate(f cmdutil.Factory, recordFlags *genericclioptions.RecordFlags, out, errOut io.Writer, cmd *cobra.Command, options *resource.FilenameOptions) error { + editOptions := editor.NewEditOptions(editor.EditBeforeCreateMode, out, errOut) + editOptions.FilenameOptions = *options + editOptions.ValidateOptions = cmdutil.ValidateOptions{ + EnableValidation: cmdutil.GetFlagBool(cmd, "validate"), } - err := editOptions.Complete(f, out, errOut, []string{}, cmd) + editOptions.Output = cmdutil.GetFlagString(cmd, "output") + editOptions.ApplyAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + editOptions.RecordFlags = recordFlags + editOptions.Include3rdParty = cmdutil.GetFlagBool(cmd, "include-extended-apis") + + err := editOptions.Complete(f, []string{}, cmd) if err != nil { return err } diff --git a/pkg/kubectl/cmd/edit.go b/pkg/kubectl/cmd/edit.go index b66758c899..c321a0e4ed 100644 --- a/pkg/kubectl/cmd/edit.go +++ b/pkg/kubectl/cmd/edit.go @@ -19,7 +19,6 @@ package cmd import ( "fmt" "io" - "runtime" "github.com/spf13/cobra" @@ -70,13 +69,10 @@ var ( ) func NewCmdEdit(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { - options := &editor.EditOptions{ - EditMode: editor.NormalEditMode, - Output: "yaml", - WindowsLineEndings: runtime.GOOS == "windows", - ValidateOptions: cmdutil.ValidateOptions{EnableValidation: true}, - Include3rdParty: true, - } + o := editor.NewEditOptions(editor.NormalEditMode, out, errOut) + o.ValidateOptions = cmdutil.ValidateOptions{EnableValidation: true} + o.Include3rdParty = true + validArgs := cmdutil.ValidArgList(f) cmd := &cobra.Command{ @@ -86,28 +82,30 @@ func NewCmdEdit(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { Long: editLong, Example: fmt.Sprintf(editExample), Run: func(cmd *cobra.Command, args []string) { - options.ChangeCause = f.Command(cmd, false) - if err := options.Complete(f, out, errOut, args, cmd); err != nil { + if err := o.Complete(f, args, cmd); err != nil { cmdutil.CheckErr(err) } - if err := options.Run(); err != nil { + if err := o.Run(); err != nil { cmdutil.CheckErr(err) } }, ValidArgs: validArgs, ArgAliases: kubectl.ResourceAliases(validArgs), } + + // bind flag structs + o.RecordFlags.AddFlags(cmd) + usage := "to use to edit the resource" - cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage) - cmdutil.AddValidateOptionFlags(cmd, &options.ValidateOptions) - cmd.Flags().StringVarP(&options.Output, "output", "o", options.Output, "Output format. One of: yaml|json.") - cmd.Flags().BoolVarP(&options.OutputPatch, "output-patch", "", options.OutputPatch, "Output the patch if the resource is edited.") - cmd.Flags().BoolVar(&options.WindowsLineEndings, "windows-line-endings", options.WindowsLineEndings, + cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage) + cmdutil.AddValidateOptionFlags(cmd, &o.ValidateOptions) + cmd.Flags().StringVarP(&o.Output, "output", "o", o.Output, "Output format. One of: yaml|json.") + cmd.Flags().BoolVarP(&o.OutputPatch, "output-patch", "", o.OutputPatch, "Output the patch if the resource is edited.") + cmd.Flags().BoolVar(&o.WindowsLineEndings, "windows-line-endings", o.WindowsLineEndings, "Defaults to the line ending native to your platform.") - cmdutil.AddApplyAnnotationVarFlags(cmd, &options.ApplyAnnotation) - cmdutil.AddRecordVarFlag(cmd, &options.Record) - cmdutil.AddInclude3rdPartyVarFlags(cmd, &options.Include3rdParty) + cmdutil.AddApplyAnnotationVarFlags(cmd, &o.ApplyAnnotation) + cmdutil.AddInclude3rdPartyVarFlags(cmd, &o.Include3rdParty) cmdutil.AddIncludeUninitializedFlag(cmd) return cmd } diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-record/3.request b/pkg/kubectl/cmd/testdata/edit/testcase-list-record/3.request index c609f20a95..ba542f24b9 100755 --- a/pkg/kubectl/cmd/testdata/edit/testcase-list-record/3.request +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-record/3.request @@ -1,10 +1,5 @@ { "data": { "new-data3": "newivalue" - }, - "metadata": { - "annotations": { - "kubernetes.io/change-cause": "edit test cmd invocation" - } } } \ No newline at end of file diff --git a/pkg/kubectl/cmd/testdata/edit/testcase-list-record/4.request b/pkg/kubectl/cmd/testdata/edit/testcase-list-record/4.request index 3520e4699f..572a718192 100755 --- a/pkg/kubectl/cmd/testdata/edit/testcase-list-record/4.request +++ b/pkg/kubectl/cmd/testdata/edit/testcase-list-record/4.request @@ -1,8 +1,5 @@ { "metadata": { - "annotations": { - "kubernetes.io/change-cause": "edit test cmd invocation" - }, "labels": { "new-label2": "foo2" } diff --git a/pkg/kubectl/cmd/util/editor/BUILD b/pkg/kubectl/cmd/util/editor/BUILD index ec7ea4d396..c0fc7acbc0 100644 --- a/pkg/kubectl/cmd/util/editor/BUILD +++ b/pkg/kubectl/cmd/util/editor/BUILD @@ -18,6 +18,7 @@ go_library( "//pkg/apis/core:go_default_library", "//pkg/kubectl:go_default_library", "//pkg/kubectl/cmd/util:go_default_library", + "//pkg/kubectl/genericclioptions:go_default_library", "//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/scheme:go_default_library", "//pkg/kubectl/util/crlf:go_default_library", diff --git a/pkg/kubectl/cmd/util/editor/editoptions.go b/pkg/kubectl/cmd/util/editor/editoptions.go index 9af8f0f33c..435ae6b01a 100644 --- a/pkg/kubectl/cmd/util/editor/editoptions.go +++ b/pkg/kubectl/cmd/util/editor/editoptions.go @@ -25,6 +25,7 @@ import ( "os" "path/filepath" "reflect" + goruntime "runtime" "strings" "github.com/evanphx/json-patch" @@ -44,6 +45,7 @@ import ( api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/kubectl" 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/scheme" "k8s.io/kubernetes/pkg/kubectl/util/crlf" @@ -53,6 +55,7 @@ import ( // EditOptions contains all the options for running edit cli command. type EditOptions struct { resource.FilenameOptions + RecordFlags *genericclioptions.RecordFlags Output string OutputPatch bool @@ -67,18 +70,32 @@ type EditOptions struct { CmdNamespace string ApplyAnnotation bool - Record bool ChangeCause string Include3rdParty bool Out io.Writer ErrOut io.Writer + Recorder genericclioptions.Recorder f cmdutil.Factory editPrinterOptions *editPrinterOptions updatedResultGetter func(data []byte) *resource.Result } +func NewEditOptions(editMode EditMode, out, errOut io.Writer) *EditOptions { + return &EditOptions{ + RecordFlags: genericclioptions.NewRecordFlags(), + + EditMode: editMode, + + Output: "yaml", + WindowsLineEndings: goruntime.GOOS == "windows", + + Out: out, + ErrOut: errOut, + } +} + type editPrinterOptions struct { printer printers.ResourcePrinter ext string @@ -86,7 +103,15 @@ type editPrinterOptions struct { } // Complete completes all the required options -func (o *EditOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, 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 + o.Recorder, err = o.RecordFlags.ToRecorder() + if err != nil { + return err + } + if o.EditMode != NormalEditMode && o.EditMode != EditBeforeCreateMode && o.EditMode != ApplyEditMode { return fmt.Errorf("unsupported edit mode %q", o.EditMode) } @@ -138,10 +163,6 @@ func (o *EditOptions) Complete(f cmdutil.Factory, out, errOut io.Writer, args [] o.CmdNamespace = cmdNamespace o.f = f - // Set up writer - o.Out = out - o.ErrOut = errOut - return nil } @@ -609,10 +630,8 @@ func (o *EditOptions) visitAnnotation(annotationVisitor resource.Visitor) error return err } } - if o.Record || cmdutil.ContainsChangeCause(info) { - if err := cmdutil.RecordChangeCause(info.Object, o.ChangeCause); err != nil { - return err - } + if err := o.Recorder.Record(info.Object); err != nil { + glog.V(4).Infof("error recording current command: %v", err) } return nil diff --git a/pkg/kubectl/genericclioptions/BUILD b/pkg/kubectl/genericclioptions/BUILD new file mode 100644 index 0000000000..080abfe414 --- /dev/null +++ b/pkg/kubectl/genericclioptions/BUILD @@ -0,0 +1,30 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = [ + "doc.go", + "record_flags.go", + ], + importpath = "k8s.io/kubernetes/pkg/kubectl/genericclioptions", + visibility = ["//visibility:public"], + deps = [ + "//vendor/github.com/spf13/cobra:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/api/meta:go_default_library", + "//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +)