mirror of https://github.com/k3s-io/k3s
Merge pull request #62858 from deads2k/cli-32-more-record-02
Automatic merge from submit-queue (batch tested with PRs 62642, 62855, 62487, 62858, 62873). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>. final record flag cleanup This ties off the remainder of the record flag uses. Trying to merge different types of patches is fraught, so I added a way to get a merge patch (not a strategic patch) back from the annotation update. @kubernetes/sig-cli-maintainers /assign @soltysh /assign @juanvallejo ```release-note NONE ```pull/8/head
commit
019c805ff2
|
@ -592,9 +592,10 @@ run_pod_tests() {
|
|||
# Post-condition: valid-pod's record annotation still contains command with --record=true
|
||||
kube::test::get_object_assert 'pod valid-pod' "{{range$annotations_field}}{{.}}:{{end}}" ".*--record=true.*"
|
||||
|
||||
### Record label change with unspecified flag and previous change already recorded
|
||||
### Record label change with specified flag and previous change already recorded
|
||||
### we are no longer tricked by data from another user into revealing more information about our client
|
||||
# Command
|
||||
kubectl label pods valid-pod new-record-change=true "${kube_flags[@]}"
|
||||
kubectl label pods valid-pod new-record-change=true --record=true "${kube_flags[@]}"
|
||||
# Post-condition: valid-pod's record annotation contains new change
|
||||
kube::test::get_object_assert 'pod valid-pod' "{{range$annotations_field}}{{.}}:{{end}}" ".*new-record-change=true.*"
|
||||
|
||||
|
|
|
@ -23,11 +23,13 @@ import (
|
|||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"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"
|
||||
)
|
||||
|
@ -72,8 +74,23 @@ var (
|
|||
kubectl expose deployment nginx --port=80 --target-port=8000`))
|
||||
)
|
||||
|
||||
type ExposeServiceOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
Recorder genericclioptions.Recorder
|
||||
}
|
||||
|
||||
func NewExposeServiceOptions() *ExposeServiceOptions {
|
||||
return &ExposeServiceOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdExposeService(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &resource.FilenameOptions{}
|
||||
o := NewExposeServiceOptions()
|
||||
|
||||
validArgs := []string{}
|
||||
resources := regexp.MustCompile(`\s*,`).Split(exposeResources, -1)
|
||||
|
@ -88,12 +105,15 @@ func NewCmdExposeService(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
Long: exposeLong,
|
||||
Example: exposeExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
err := RunExpose(f, out, cmd, args, options)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.RunExpose(f, out, cmd, args))
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().String("generator", "service/v2", i18n.T("The name of the API generator to use. There are 2 generators: 'service/v1' and 'service/v2'. The only difference between them is that service port in v1 is named 'default', while it is left unnamed in v2. Default is 'service/v2'."))
|
||||
cmd.Flags().String("protocol", "", i18n.T("The network protocol for the service to be created. Default is 'TCP'."))
|
||||
|
@ -112,14 +132,25 @@ func NewCmdExposeService(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
cmd.Flags().String("cluster-ip", "", i18n.T("ClusterIP to be assigned to the service. Leave empty to auto-allocate, or set to 'None' to create a headless service."))
|
||||
|
||||
usage := "identifying the resource to expose a service"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *resource.FilenameOptions) error {
|
||||
func (o *ExposeServiceOptions) 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
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *ExposeServiceOptions) RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||
namespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -130,7 +161,7 @@ func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
|||
Internal().
|
||||
ContinueOnError().
|
||||
NamespaceParam(namespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options).
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
ResourceTypeOrNameArgs(false, args...).
|
||||
Flatten().
|
||||
Do()
|
||||
|
@ -247,10 +278,8 @@ func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
if err := cmdutil.RecordChangeCause(object, f.Command(cmd, false)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := o.Recorder.Record(object); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
info.Refresh(object, true)
|
||||
if cmdutil.GetDryRunFlag(cmd) {
|
||||
|
|
|
@ -37,6 +37,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"
|
||||
)
|
||||
|
@ -45,6 +46,7 @@ import (
|
|||
type LabelOptions struct {
|
||||
// Filename options
|
||||
resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
// Common user flags
|
||||
overwrite bool
|
||||
|
@ -61,6 +63,8 @@ type LabelOptions struct {
|
|||
newLabels map[string]string
|
||||
removeLabels []string
|
||||
|
||||
Recorder genericclioptions.Recorder
|
||||
|
||||
// Common shared fields
|
||||
out io.Writer
|
||||
errout io.Writer
|
||||
|
@ -96,10 +100,19 @@ var (
|
|||
kubectl label pods foo bar-`))
|
||||
)
|
||||
|
||||
func NewCmdLabel(f cmdutil.Factory, out, errout io.Writer) *cobra.Command {
|
||||
options := &LabelOptions{
|
||||
errout: errout,
|
||||
func NewLabelOptions(out, errOut io.Writer) *LabelOptions {
|
||||
return &LabelOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
|
||||
out: out,
|
||||
errout: errOut,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdLabel(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
o := NewLabelOptions(out, errOut)
|
||||
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
|
||||
|
@ -110,36 +123,45 @@ func NewCmdLabel(f cmdutil.Factory, out, errout io.Writer) *cobra.Command {
|
|||
Long: fmt.Sprintf(labelLong, validation.LabelValueMaxLength),
|
||||
Example: labelExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
if err := options.Complete(out, cmd, args); err != nil {
|
||||
if err := o.Complete(f, cmd, args); err != nil {
|
||||
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, err.Error()))
|
||||
}
|
||||
if err := options.Validate(); err != nil {
|
||||
if err := o.Validate(); err != nil {
|
||||
cmdutil.CheckErr(cmdutil.UsageErrorf(cmd, err.Error()))
|
||||
}
|
||||
cmdutil.CheckErr(options.RunLabel(f, cmd))
|
||||
cmdutil.CheckErr(o.RunLabel(f, cmd))
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmd.Flags().BoolVar(&options.overwrite, "overwrite", options.overwrite, "If true, allow labels to be overwritten, otherwise reject label updates that overwrite existing labels.")
|
||||
cmd.Flags().BoolVar(&options.list, "list", options.list, "If true, display the labels for a given resource.")
|
||||
cmd.Flags().BoolVar(&options.local, "local", options.local, "If true, label 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().BoolVar(&options.all, "all", options.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 labels update will only succeed if this is the current resource-version for the object. Only valid when specifying a single resource."))
|
||||
cmd.Flags().BoolVar(&o.overwrite, "overwrite", o.overwrite, "If true, allow labels to be overwritten, otherwise reject label updates that overwrite existing labels.")
|
||||
cmd.Flags().BoolVar(&o.list, "list", o.list, "If true, display the labels for a given resource.")
|
||||
cmd.Flags().BoolVar(&o.local, "local", o.local, "If true, label will NOT contact api-server but run locally.")
|
||||
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(&o.all, "all", o.all, "Select all resources, including uninitialized ones, in the namespace of the specified resource types")
|
||||
cmd.Flags().StringVar(&o.resourceVersion, "resource-version", o.resourceVersion, i18n.T("If non-empty, the labels 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 labels"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Complete adapts from the command line args and factory to the data required.
|
||||
func (o *LabelOptions) Complete(out io.Writer, cmd *cobra.Command, args []string) (err error) {
|
||||
o.out = out
|
||||
func (o *LabelOptions) 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.outputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
o.dryrun = cmdutil.GetDryRunFlag(cmd)
|
||||
|
||||
|
@ -178,8 +200,6 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
|||
return err
|
||||
}
|
||||
|
||||
changeCause := f.Command(cmd, false)
|
||||
|
||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||
b := f.NewBuilder().
|
||||
Unstructured().
|
||||
|
@ -242,10 +262,8 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
|||
if err := labelFunc(obj, o.overwrite, o.resourceVersion, o.newLabels, o.removeLabels); err != nil {
|
||||
return err
|
||||
}
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
if err := cmdutil.RecordChangeCause(obj, changeCause); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := o.Recorder.Record(obj); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
newData, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
|
|
|
@ -29,7 +29,6 @@ import (
|
|||
"k8s.io/client-go/rest/fake"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||
)
|
||||
|
||||
|
@ -335,8 +334,8 @@ func TestLabelErrors(t *testing.T) {
|
|||
for k, v := range testCase.flags {
|
||||
cmd.Flags().Set(k, v)
|
||||
}
|
||||
opts := LabelOptions{}
|
||||
err := opts.Complete(buf, cmd, testCase.args)
|
||||
opts := NewLabelOptions(buf, buf)
|
||||
err := opts.Complete(tf, cmd, testCase.args)
|
||||
if err == nil {
|
||||
err = opts.Validate()
|
||||
}
|
||||
|
@ -392,9 +391,9 @@ func TestLabelForResourceFromFile(t *testing.T) {
|
|||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdLabel(tf, buf, buf)
|
||||
opts := LabelOptions{FilenameOptions: resource.FilenameOptions{
|
||||
Filenames: []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}}}
|
||||
err := opts.Complete(buf, cmd, []string{"a=b"})
|
||||
opts := NewLabelOptions(buf, buf)
|
||||
opts.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
||||
err := opts.Complete(tf, cmd, []string{"a=b"})
|
||||
if err == nil {
|
||||
err = opts.Validate()
|
||||
}
|
||||
|
@ -425,10 +424,10 @@ func TestLabelLocal(t *testing.T) {
|
|||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
cmd := NewCmdLabel(tf, buf, buf)
|
||||
opts := LabelOptions{FilenameOptions: resource.FilenameOptions{
|
||||
Filenames: []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}},
|
||||
local: true}
|
||||
err := opts.Complete(buf, cmd, []string{"a=b"})
|
||||
opts := NewLabelOptions(buf, buf)
|
||||
opts.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
||||
opts.local = true
|
||||
err := opts.Complete(tf, cmd, []string{"a=b"})
|
||||
if err == nil {
|
||||
err = opts.Validate()
|
||||
}
|
||||
|
@ -482,9 +481,10 @@ func TestLabelMultipleObjects(t *testing.T) {
|
|||
tf.ClientConfigVal = defaultClientConfig()
|
||||
|
||||
buf := bytes.NewBuffer([]byte{})
|
||||
opts := LabelOptions{all: true}
|
||||
opts := NewLabelOptions(buf, buf)
|
||||
opts.all = true
|
||||
cmd := NewCmdLabel(tf, buf, buf)
|
||||
err := opts.Complete(buf, cmd, []string{"pods", "a=b"})
|
||||
err := opts.Complete(tf, cmd, []string{"pods", "a=b"})
|
||||
if err == nil {
|
||||
err = opts.Validate()
|
||||
}
|
||||
|
|
|
@ -36,6 +36,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/scheme"
|
||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
||||
|
@ -47,10 +48,13 @@ var patchTypes = map[string]types.PatchType{"json": types.JSONPatchType, "merge"
|
|||
// referencing the cmd.Flags()
|
||||
type PatchOptions struct {
|
||||
resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
Local bool
|
||||
DryRun bool
|
||||
|
||||
Recorder genericclioptions.Recorder
|
||||
|
||||
OutputFormat string
|
||||
}
|
||||
|
||||
|
@ -79,8 +83,16 @@ var (
|
|||
kubectl patch pod valid-pod --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value":"new image"}]'`))
|
||||
)
|
||||
|
||||
func NewPatchOptions() *PatchOptions {
|
||||
return &PatchOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||
options := &PatchOptions{}
|
||||
o := NewPatchOptions()
|
||||
validArgs := cmdutil.ValidArgList(f)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
|
@ -90,32 +102,47 @@ func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||
Long: patchLong,
|
||||
Example: patchExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
options.OutputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
options.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
||||
err := RunPatch(f, out, cmd, args, options)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(o.RunPatch(f, out, cmd, args))
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||
}
|
||||
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
|
||||
cmd.Flags().StringP("patch", "p", "", "The patch to be applied to the resource JSON file.")
|
||||
cmd.MarkFlagRequired("patch")
|
||||
cmd.Flags().String("type", "strategic", fmt.Sprintf("The type of patch being provided; one of %v", sets.StringKeySet(patchTypes).List()))
|
||||
cmdutil.AddPrinterFlags(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
cmdutil.AddDryRunFlag(cmd)
|
||||
|
||||
usage := "identifying the resource to update"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
|
||||
cmd.Flags().BoolVar(&options.Local, "local", options.Local, "If true, patch will operate on the content of the file, not the server-side resource.")
|
||||
cmd.Flags().BoolVar(&o.Local, "local", o.Local, "If true, patch will operate on the content of the file, not the server-side resource.")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string, options *PatchOptions) error {
|
||||
func (o *PatchOptions) 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.OutputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||
o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (o *PatchOptions) RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []string) error {
|
||||
switch {
|
||||
case options.Local && len(args) != 0:
|
||||
case o.Local && len(args) != 0:
|
||||
return fmt.Errorf("cannot specify --local and server resources")
|
||||
}
|
||||
|
||||
|
@ -148,7 +175,7 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
|||
Unstructured().
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, &options.FilenameOptions).
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
ResourceTypeOrNameArgs(false, args...).
|
||||
Flatten().
|
||||
Do()
|
||||
|
@ -169,38 +196,36 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
|||
return err
|
||||
}
|
||||
|
||||
if !options.Local && !options.DryRun {
|
||||
if !o.Local && !o.DryRun {
|
||||
helper := resource.NewHelper(client, mapping)
|
||||
patchedObj, err := helper.Patch(namespace, name, patchType, patchBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Record the change as a second patch to avoid trying to merge with a user's patch data
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
// Copy the resource info and update with the result of applying the user's patch
|
||||
infoCopy := *info
|
||||
infoCopy.Object = patchedObj
|
||||
if patch, patchType, err := cmdutil.ChangeResourcePatch(&infoCopy, f.Command(cmd, true)); err == nil {
|
||||
if recordedObj, err := helper.Patch(info.Namespace, info.Name, patchType, patch); err != nil {
|
||||
glog.V(4).Infof("error recording reason: %v", err)
|
||||
} else {
|
||||
patchedObj = recordedObj
|
||||
}
|
||||
|
||||
didPatch := !reflect.DeepEqual(info.Object, patchedObj)
|
||||
|
||||
// if the recorder makes a change, compute and create another patch
|
||||
if mergePatch, err := o.Recorder.MakeRecordMergePatch(patchedObj); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
} else if len(mergePatch) > 0 {
|
||||
if recordedObj, err := helper.Patch(info.Namespace, info.Name, types.MergePatchType, mergePatch); err != nil {
|
||||
glog.V(4).Infof("error recording reason: %v", err)
|
||||
} else {
|
||||
patchedObj = recordedObj
|
||||
}
|
||||
}
|
||||
count++
|
||||
|
||||
didPatch := !reflect.DeepEqual(info.Object, patchedObj)
|
||||
|
||||
// After computing whether we changed data, refresh the resource info with the resulting object
|
||||
if err := info.Refresh(patchedObj, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(options.OutputFormat) > 0 && options.OutputFormat != "name" {
|
||||
if len(o.OutputFormat) > 0 && o.OutputFormat != "name" {
|
||||
return cmdutil.PrintObject(cmd, info.Object, out)
|
||||
}
|
||||
cmdutil.PrintSuccess(options.OutputFormat == "name", out, info.Object, false, patchOperation(didPatch))
|
||||
cmdutil.PrintSuccess(o.OutputFormat == "name", out, info.Object, false, patchOperation(didPatch))
|
||||
|
||||
// if object was not successfully patched, exit with error code 1
|
||||
if !didPatch {
|
||||
|
@ -239,11 +264,11 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
|||
}
|
||||
}
|
||||
|
||||
if len(options.OutputFormat) > 0 && options.OutputFormat != "name" {
|
||||
if len(o.OutputFormat) > 0 && o.OutputFormat != "name" {
|
||||
return cmdutil.PrintObject(cmd, info.Object, out)
|
||||
}
|
||||
|
||||
cmdutil.PrintSuccess(options.OutputFormat == "name", out, info.Object, options.DryRun, patchOperation(didPatch))
|
||||
cmdutil.PrintSuccess(o.OutputFormat == "name", out, info.Object, o.DryRun, patchOperation(didPatch))
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
@ -33,6 +33,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"
|
||||
"k8s.io/kubernetes/pkg/kubectl/validation"
|
||||
|
@ -64,39 +65,43 @@ var (
|
|||
kubectl replace --force -f ./pod.json`))
|
||||
)
|
||||
|
||||
type ReplaceOpts struct {
|
||||
type ReplaceOptions struct {
|
||||
PrintFlags *printers.PrintFlags
|
||||
DeleteFlags *DeleteFlags
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
DeleteOptions *DeleteOptions
|
||||
|
||||
PrintObj func(obj runtime.Object) error
|
||||
|
||||
createAnnotation bool
|
||||
changeCause string
|
||||
validate bool
|
||||
|
||||
Schema validation.Schema
|
||||
Builder func() *resource.Builder
|
||||
BuilderArgs []string
|
||||
|
||||
ShouldRecord func(info *resource.Info) bool
|
||||
|
||||
Namespace string
|
||||
EnforceNamespace bool
|
||||
|
||||
Recorder genericclioptions.Recorder
|
||||
|
||||
Out io.Writer
|
||||
ErrOut io.Writer
|
||||
}
|
||||
|
||||
func NewCmdReplace(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := &ReplaceOpts{
|
||||
func NewReplaceOptions(out, errOut io.Writer) *ReplaceOptions {
|
||||
return &ReplaceOptions{
|
||||
PrintFlags: printers.NewPrintFlags("replaced"),
|
||||
DeleteFlags: NewDeleteFlags("to use to replace the resource."),
|
||||
|
||||
Out: out,
|
||||
ErrOut: errOut,
|
||||
}
|
||||
}
|
||||
|
||||
func NewCmdReplace(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
o := NewReplaceOptions(out, errOut)
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "replace -f FILENAME",
|
||||
|
@ -106,32 +111,35 @@ func NewCmdReplace(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
|||
Example: replaceExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(options.Validate(cmd))
|
||||
cmdutil.CheckErr(options.Run())
|
||||
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||
cmdutil.CheckErr(o.Validate(cmd))
|
||||
cmdutil.CheckErr(o.Run())
|
||||
},
|
||||
}
|
||||
|
||||
options.PrintFlags.AddFlags(cmd)
|
||||
options.DeleteFlags.AddFlags(cmd)
|
||||
o.PrintFlags.AddFlags(cmd)
|
||||
o.DeleteFlags.AddFlags(cmd)
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
|
||||
cmd.MarkFlagRequired("filename")
|
||||
cmdutil.AddValidateFlags(cmd)
|
||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *ReplaceOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
o.validate = cmdutil.GetFlagBool(cmd, "validate")
|
||||
o.changeCause = f.Command(cmd, false)
|
||||
o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
||||
func (o *ReplaceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||
var err error
|
||||
|
||||
o.ShouldRecord = func(info *resource.Info) bool {
|
||||
return cmdutil.ShouldRecord(cmd, info)
|
||||
o.RecordFlags.Complete(f.Command(cmd, false))
|
||||
o.Recorder, err = o.RecordFlags.ToRecorder()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
o.validate = cmdutil.GetFlagBool(cmd, "validate")
|
||||
o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
||||
|
||||
printer, err := o.PrintFlags.ToPrinter()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -173,7 +181,7 @@ func (o *ReplaceOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []str
|
|||
return nil
|
||||
}
|
||||
|
||||
func (o *ReplaceOpts) Validate(cmd *cobra.Command) error {
|
||||
func (o *ReplaceOptions) Validate(cmd *cobra.Command) error {
|
||||
if o.DeleteOptions.GracePeriod >= 0 && !o.DeleteOptions.ForceDeletion {
|
||||
return fmt.Errorf("--grace-period must have --force specified")
|
||||
}
|
||||
|
@ -189,7 +197,7 @@ func (o *ReplaceOpts) Validate(cmd *cobra.Command) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (o *ReplaceOpts) Run() error {
|
||||
func (o *ReplaceOptions) Run() error {
|
||||
if o.DeleteOptions.ForceDeletion {
|
||||
return o.forceReplace()
|
||||
}
|
||||
|
@ -215,10 +223,8 @@ func (o *ReplaceOpts) Run() error {
|
|||
return cmdutil.AddSourceToErr("replacing", info.Source, err)
|
||||
}
|
||||
|
||||
if o.ShouldRecord(info) {
|
||||
if err := cmdutil.RecordChangeCause(info.Object, o.changeCause); err != nil {
|
||||
return cmdutil.AddSourceToErr("replacing", info.Source, err)
|
||||
}
|
||||
if err := o.Recorder.Record(info.Object); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
|
||||
// Serialize the object with the annotation applied.
|
||||
|
@ -232,7 +238,7 @@ func (o *ReplaceOpts) Run() error {
|
|||
})
|
||||
}
|
||||
|
||||
func (o *ReplaceOpts) forceReplace() error {
|
||||
func (o *ReplaceOptions) forceReplace() error {
|
||||
for i, filename := range o.DeleteOptions.FilenameOptions.Filenames {
|
||||
if filename == "-" {
|
||||
tempDir, err := ioutil.TempDir("", "kubectl_replace_")
|
||||
|
@ -313,10 +319,8 @@ func (o *ReplaceOpts) forceReplace() error {
|
|||
return err
|
||||
}
|
||||
|
||||
if o.ShouldRecord(info) {
|
||||
if err := cmdutil.RecordChangeCause(info.Object, o.changeCause); err != nil {
|
||||
return cmdutil.AddSourceToErr("replacing", info.Source, err)
|
||||
}
|
||||
if err := o.Recorder.Record(info.Object); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
}
|
||||
|
||||
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
|
||||
|
|
|
@ -22,11 +22,14 @@ import (
|
|||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
batchclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/batch/internalversion"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
"k8s.io/kubernetes/pkg/kubectl/cmd/scalejob"
|
||||
"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"
|
||||
)
|
||||
|
@ -58,9 +61,24 @@ var (
|
|||
kubectl scale --replicas=3 statefulset/web`))
|
||||
)
|
||||
|
||||
type ScaleOptions struct {
|
||||
FilenameOptions resource.FilenameOptions
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
Recorder genericclioptions.Recorder
|
||||
}
|
||||
|
||||
func NewScaleOptions() *ScaleOptions {
|
||||
return &ScaleOptions{
|
||||
RecordFlags: genericclioptions.NewRecordFlags(),
|
||||
|
||||
Recorder: genericclioptions.NoopRecorder{},
|
||||
}
|
||||
}
|
||||
|
||||
// NewCmdScale returns a cobra command with the appropriate configuration and flags to run scale
|
||||
func NewCmdScale(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||
options := &resource.FilenameOptions{}
|
||||
o := NewScaleOptions()
|
||||
|
||||
validArgs := []string{"deployment", "replicaset", "replicationcontroller", "statefulset"}
|
||||
argAliases := kubectl.ResourceAliases(validArgs)
|
||||
|
@ -72,14 +90,17 @@ func NewCmdScale(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
|||
Long: scaleLong,
|
||||
Example: scaleExample,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
||||
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
|
||||
err := RunScale(f, out, errOut, cmd, args, shortOutput, options)
|
||||
cmdutil.CheckErr(err)
|
||||
cmdutil.CheckErr(o.RunScale(f, out, errOut, cmd, args, shortOutput))
|
||||
},
|
||||
ValidArgs: validArgs,
|
||||
ArgAliases: argAliases,
|
||||
}
|
||||
|
||||
o.RecordFlags.AddFlags(cmd)
|
||||
|
||||
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
|
||||
cmd.Flags().Bool("all", false, "Select all resources in the namespace of the specified resource types")
|
||||
cmd.Flags().String("resource-version", "", i18n.T("Precondition for resource version. Requires that the current resource version match this value in order to scale."))
|
||||
|
@ -88,15 +109,26 @@ func NewCmdScale(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
|||
cmd.MarkFlagRequired("replicas")
|
||||
cmd.Flags().Duration("timeout", 0, "The length of time to wait before giving up on a scale operation, zero means don't wait. Any other values should contain a corresponding time unit (e.g. 1s, 2m, 3h).")
|
||||
cmdutil.AddOutputFlagsForMutation(cmd)
|
||||
cmdutil.AddRecordFlag(cmd)
|
||||
|
||||
usage := "identifying the resource to set a new size"
|
||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
||||
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (o *ScaleOptions) 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
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// RunScale executes the scaling
|
||||
func RunScale(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args []string, shortOutput bool, options *resource.FilenameOptions) error {
|
||||
func (o *ScaleOptions) RunScale(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args []string, shortOutput bool) error {
|
||||
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -114,7 +146,7 @@ func RunScale(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args
|
|||
Unstructured().
|
||||
ContinueOnError().
|
||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||
FilenameParam(enforceNamespace, options).
|
||||
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||
ResourceTypeOrNameArgs(all, args...).
|
||||
Flatten().
|
||||
LabelSelectorParam(selector).
|
||||
|
@ -180,22 +212,20 @@ func RunScale(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args
|
|||
}
|
||||
}
|
||||
|
||||
if cmdutil.ShouldRecord(cmd, info) {
|
||||
patchBytes, patchType, err := cmdutil.ChangeResourcePatch(info, f.Command(cmd, true))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mapping := info.ResourceMapping()
|
||||
// if the recorder makes a change, compute and create another patch
|
||||
if mergePatch, err := o.Recorder.MakeRecordMergePatch(info.Object); err != nil {
|
||||
glog.V(4).Infof("error recording current command: %v", err)
|
||||
} else if len(mergePatch) > 0 {
|
||||
client, err := f.UnstructuredClientForMapping(mapping)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
helper := resource.NewHelper(client, mapping)
|
||||
_, err = helper.Patch(info.Namespace, info.Name, patchType, patchBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
if _, err := helper.Patch(info.Namespace, info.Name, types.MergePatchType, mergePatch); err != nil {
|
||||
glog.V(4).Infof("error recording reason: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
counter++
|
||||
cmdutil.PrintSuccess(shortOutput, out, info.Object, false, "scaled")
|
||||
return nil
|
||||
|
|
|
@ -122,8 +122,6 @@ type EnvOptions struct {
|
|||
Builder *resource.Builder
|
||||
Infos []*resource.Info
|
||||
|
||||
Cmd *cobra.Command
|
||||
|
||||
UpdatePodSpecForObject func(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error)
|
||||
}
|
||||
|
||||
|
@ -193,7 +191,7 @@ func (o *EnvOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
|
|||
}
|
||||
resources, envArgs, ok := envutil.SplitEnvironmentFromResources(args)
|
||||
if !ok {
|
||||
return cmdutil.UsageErrorf(o.Cmd, "all resources must be specified before environment changes: %s", strings.Join(args, " "))
|
||||
return cmdutil.UsageErrorf(cmd, "all resources must be specified before environment changes: %s", strings.Join(args, " "))
|
||||
}
|
||||
if len(o.Filenames) == 0 && len(resources) < 1 {
|
||||
return cmdutil.UsageErrorf(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>")
|
||||
|
@ -213,7 +211,6 @@ func (o *EnvOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
|
|||
|
||||
o.EnvArgs = envArgs
|
||||
o.Resources = resources
|
||||
o.Cmd = cmd
|
||||
|
||||
if o.DryRun {
|
||||
// TODO(juanvallejo): This can be cleaned up even further by creating
|
||||
|
@ -229,7 +226,7 @@ func (o *EnvOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
|
|||
o.PrintObj = printer.PrintObj
|
||||
|
||||
if o.List && len(o.Output) > 0 {
|
||||
return cmdutil.UsageErrorf(o.Cmd, "--list and --output may not be specified together")
|
||||
return cmdutil.UsageErrorf(cmd, "--list and --output may not be specified together")
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -50,9 +50,7 @@ type SetImageOptions struct {
|
|||
DryRun bool
|
||||
All bool
|
||||
Output string
|
||||
ChangeCause string
|
||||
Local bool
|
||||
Cmd *cobra.Command
|
||||
ResolveImage func(in string) (string, error)
|
||||
|
||||
PrintObj printers.ResourcePrinterFunc
|
||||
|
@ -138,11 +136,9 @@ func (o *SetImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
|
|||
}
|
||||
|
||||
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
|
||||
o.ChangeCause = f.Command(cmd, false)
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
o.Output = cmdutil.GetFlagString(cmd, "output")
|
||||
o.ResolveImage = f.ResolveImage
|
||||
o.Cmd = cmd
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
|
|
|
@ -75,9 +75,7 @@ type SetResourcesOptions struct {
|
|||
ContainerSelector string
|
||||
Output string
|
||||
All bool
|
||||
ChangeCause string
|
||||
Local bool
|
||||
Cmd *cobra.Command
|
||||
|
||||
DryRun bool
|
||||
|
||||
|
@ -157,9 +155,7 @@ func (o *SetResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, ar
|
|||
|
||||
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
|
||||
o.Output = cmdutil.GetFlagString(cmd, "output")
|
||||
o.ChangeCause = f.Command(cmd, false)
|
||||
o.Cmd = cmd
|
||||
o.DryRun = cmdutil.GetDryRunFlag(o.Cmd)
|
||||
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||
|
||||
if o.DryRun {
|
||||
o.PrintFlags.Complete("%s (dry run)")
|
||||
|
|
|
@ -45,12 +45,10 @@ type SetSelectorOptions struct {
|
|||
PrintFlags *printers.PrintFlags
|
||||
RecordFlags *genericclioptions.RecordFlags
|
||||
|
||||
local bool
|
||||
dryrun bool
|
||||
all bool
|
||||
record bool
|
||||
changeCause string
|
||||
output string
|
||||
local bool
|
||||
dryrun bool
|
||||
all bool
|
||||
output string
|
||||
|
||||
resources []string
|
||||
selector *metav1.LabelSelector
|
||||
|
@ -141,7 +139,6 @@ func (o *SetSelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg
|
|||
return err
|
||||
}
|
||||
|
||||
o.changeCause = f.Command(cmd, false)
|
||||
mapper, _ := f.Object()
|
||||
o.mapper = mapper
|
||||
|
||||
|
|
|
@ -65,12 +65,9 @@ type SetServiceAccountOptions struct {
|
|||
out io.Writer
|
||||
err io.Writer
|
||||
dryRun bool
|
||||
cmd *cobra.Command
|
||||
shortOutput bool
|
||||
all bool
|
||||
record bool
|
||||
output string
|
||||
changeCause string
|
||||
local bool
|
||||
updatePodSpecForObject func(runtime.Object, func(*v1.PodSpec) error) (bool, error)
|
||||
infos []*resource.Info
|
||||
|
@ -132,12 +129,9 @@ func (o *SetServiceAccountOptions) Complete(f cmdutil.Factory, cmd *cobra.Comman
|
|||
}
|
||||
|
||||
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)")
|
||||
|
|
|
@ -57,11 +57,8 @@ go_library(
|
|||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/types:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/errors:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/strategicpatch:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/yaml:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
|
||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||
|
|
|
@ -34,13 +34,9 @@ import (
|
|||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
||||
"k8s.io/apimachinery/pkg/util/yaml"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/kubernetes/pkg/kubectl"
|
||||
|
@ -517,64 +513,10 @@ func UpdateObject(info *resource.Info, codec runtime.Codec, updateFn func(runtim
|
|||
return info.Object, nil
|
||||
}
|
||||
|
||||
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.")
|
||||
}
|
||||
|
||||
func GetRecordFlag(cmd *cobra.Command) bool {
|
||||
return GetFlagBool(cmd, "record")
|
||||
}
|
||||
|
||||
func GetDryRunFlag(cmd *cobra.Command) bool {
|
||||
return GetFlagBool(cmd, "dry-run")
|
||||
}
|
||||
|
||||
// RecordChangeCause annotate change-cause to input runtime object.
|
||||
func RecordChangeCause(obj runtime.Object, changeCause string) error {
|
||||
accessor, err := meta.Accessor(obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
annotations := accessor.GetAnnotations()
|
||||
if annotations == nil {
|
||||
annotations = make(map[string]string)
|
||||
}
|
||||
annotations[kubectl.ChangeCauseAnnotation] = changeCause
|
||||
accessor.SetAnnotations(annotations)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ChangeResourcePatch creates a patch between the origin input resource info
|
||||
// and the annotated with change-cause input resource info.
|
||||
func ChangeResourcePatch(info *resource.Info, changeCause string) ([]byte, types.PatchType, error) {
|
||||
// Get a versioned object
|
||||
obj, err := info.Mapping.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
|
||||
if err != nil {
|
||||
return nil, types.StrategicMergePatchType, err
|
||||
}
|
||||
|
||||
oldData, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, types.StrategicMergePatchType, err
|
||||
}
|
||||
if err := RecordChangeCause(obj, changeCause); err != nil {
|
||||
return nil, types.StrategicMergePatchType, err
|
||||
}
|
||||
newData, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, types.StrategicMergePatchType, err
|
||||
}
|
||||
|
||||
switch obj := obj.(type) {
|
||||
case *unstructured.Unstructured:
|
||||
patch, err := jsonpatch.CreateMergePatch(oldData, newData)
|
||||
return patch, types.MergePatchType, err
|
||||
default:
|
||||
patch, err := strategicpatch.CreateTwoWayMergePatch(oldData, newData, obj)
|
||||
return patch, types.StrategicMergePatchType, err
|
||||
}
|
||||
}
|
||||
|
||||
// ContainsChangeCause checks if input resource info contains change-cause annotation.
|
||||
func ContainsChangeCause(info *resource.Info) bool {
|
||||
annotations, err := info.Mapping.MetadataAccessor.Annotations(info.Object)
|
||||
|
@ -584,11 +526,6 @@ func ContainsChangeCause(info *resource.Info) bool {
|
|||
return len(annotations[kubectl.ChangeCauseAnnotation]) > 0
|
||||
}
|
||||
|
||||
// ShouldRecord checks if we should record current change cause
|
||||
func ShouldRecord(cmd *cobra.Command, info *resource.Info) bool {
|
||||
return GetRecordFlag(cmd) || (ContainsChangeCause(info) && !cmd.Flags().Changed("record"))
|
||||
}
|
||||
|
||||
// GetResourcesAndPairs retrieves resources and "KEY=VALUE or KEY-" pair args from given args
|
||||
func GetResourcesAndPairs(args []string, pairType string) (resources []string, pairArgs []string, err error) {
|
||||
foundPair := false
|
||||
|
@ -703,22 +640,6 @@ func RequireNoArguments(c *cobra.Command, args []string) {
|
|||
}
|
||||
}
|
||||
|
||||
// OutputsRawFormat determines if a command's output format is machine parsable
|
||||
// or returns false if it is human readable (name, wide, etc.)
|
||||
func OutputsRawFormat(cmd *cobra.Command) bool {
|
||||
output := GetFlagString(cmd, "output")
|
||||
if output == "json" ||
|
||||
output == "yaml" ||
|
||||
output == "go-template" ||
|
||||
output == "go-template-file" ||
|
||||
output == "jsonpath" ||
|
||||
output == "jsonpath-file" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// StripComments will transform a YAML file into JSON, thus dropping any comments
|
||||
// in it. Note that if the given file has a syntax error, the transformation will
|
||||
// fail and we will manually drop all comments from the file.
|
||||
|
|
|
@ -19,7 +19,6 @@ package util
|
|||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
@ -195,19 +194,6 @@ func TestMerge(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
type fileHandler struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
func (f *fileHandler) ServeHTTP(res http.ResponseWriter, req *http.Request) {
|
||||
if req.URL.Path == "/error" {
|
||||
res.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
res.WriteHeader(http.StatusOK)
|
||||
res.Write(f.data)
|
||||
}
|
||||
|
||||
type checkErrTestCase struct {
|
||||
err error
|
||||
expectedErr string
|
||||
|
|
|
@ -9,9 +9,11 @@ go_library(
|
|||
importpath = "k8s.io/kubernetes/pkg/kubectl/genericclioptions",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//vendor/github.com/evanphx/json-patch:go_default_library",
|
||||
"//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",
|
||||
"//vendor/k8s.io/apimachinery/pkg/util/json:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
|
@ -17,10 +17,12 @@ limitations under the License.
|
|||
package genericclioptions
|
||||
|
||||
import (
|
||||
"github.com/evanphx/json-patch"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/json"
|
||||
)
|
||||
|
||||
// ChangeCauseAnnotation is the annotation indicating a guess at "why" something was changed
|
||||
|
@ -92,6 +94,7 @@ func NewRecordFlags() *RecordFlags {
|
|||
type Recorder interface {
|
||||
// Record records why a runtime.Object was changed in an annotation.
|
||||
Record(runtime.Object) error
|
||||
MakeRecordMergePatch(runtime.Object) ([]byte, error)
|
||||
}
|
||||
|
||||
// NoopRecorder does nothing. It is a "do nothing" that can be returned so code doesn't switch on it.
|
||||
|
@ -102,6 +105,11 @@ func (r NoopRecorder) Record(obj runtime.Object) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// MakeRecordMergePatch implements Recorder
|
||||
func (r NoopRecorder) MakeRecordMergePatch(obj runtime.Object) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// ChangeCauseRecorder annotates a "change-cause" to an input runtime object
|
||||
type ChangeCauseRecorder struct {
|
||||
changeCause string
|
||||
|
@ -122,3 +130,23 @@ func (r *ChangeCauseRecorder) Record(obj runtime.Object) error {
|
|||
accessor.SetAnnotations(annotations)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MakeRecordMergePatch produces a merge patch for updating the recording annotation.
|
||||
func (r *ChangeCauseRecorder) MakeRecordMergePatch(obj runtime.Object) ([]byte, error) {
|
||||
// copy so we don't mess with the original
|
||||
objCopy := obj.DeepCopyObject()
|
||||
if err := r.Record(objCopy); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oldData, err := json.Marshal(obj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newData, err := json.Marshal(objCopy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return jsonpatch.CreateMergePatch(oldData, newData)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue