mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-21 17:48:01 +00:00
final record flag cleanup
This commit is contained in:
parent
3856891198
commit
ecd9a6be2e
@ -592,9 +592,10 @@ run_pod_tests() {
|
|||||||
# Post-condition: valid-pod's record annotation still contains command with --record=true
|
# 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.*"
|
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
|
# 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
|
# 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.*"
|
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/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/validation"
|
"k8s.io/apimachinery/pkg/util/validation"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
@ -72,8 +74,23 @@ var (
|
|||||||
kubectl expose deployment nginx --port=80 --target-port=8000`))
|
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 {
|
func NewCmdExposeService(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||||
options := &resource.FilenameOptions{}
|
o := NewExposeServiceOptions()
|
||||||
|
|
||||||
validArgs := []string{}
|
validArgs := []string{}
|
||||||
resources := regexp.MustCompile(`\s*,`).Split(exposeResources, -1)
|
resources := regexp.MustCompile(`\s*,`).Split(exposeResources, -1)
|
||||||
@ -88,12 +105,15 @@ func NewCmdExposeService(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
Long: exposeLong,
|
Long: exposeLong,
|
||||||
Example: exposeExample,
|
Example: exposeExample,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
err := RunExpose(f, out, cmd, args, options)
|
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(o.RunExpose(f, out, cmd, args))
|
||||||
},
|
},
|
||||||
ValidArgs: validArgs,
|
ValidArgs: validArgs,
|
||||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
o.RecordFlags.AddFlags(cmd)
|
||||||
|
|
||||||
cmdutil.AddPrinterFlags(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("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'."))
|
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."))
|
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"
|
usage := "identifying the resource to expose a service"
|
||||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||||
cmdutil.AddDryRunFlag(cmd)
|
cmdutil.AddDryRunFlag(cmd)
|
||||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||||
cmdutil.AddRecordFlag(cmd)
|
|
||||||
return 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()
|
namespace, enforceNamespace, err := f.DefaultNamespace()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -130,7 +161,7 @@ func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
|||||||
Internal().
|
Internal().
|
||||||
ContinueOnError().
|
ContinueOnError().
|
||||||
NamespaceParam(namespace).DefaultNamespace().
|
NamespaceParam(namespace).DefaultNamespace().
|
||||||
FilenameParam(enforceNamespace, options).
|
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||||
ResourceTypeOrNameArgs(false, args...).
|
ResourceTypeOrNameArgs(false, args...).
|
||||||
Flatten().
|
Flatten().
|
||||||
Do()
|
Do()
|
||||||
@ -247,10 +278,8 @@ func RunExpose(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []stri
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmdutil.ShouldRecord(cmd, info) {
|
if err := o.Recorder.Record(object); err != nil {
|
||||||
if err := cmdutil.RecordChangeCause(object, f.Command(cmd, false)); err != nil {
|
glog.V(4).Infof("error recording current command: %v", err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
info.Refresh(object, true)
|
info.Refresh(object, true)
|
||||||
if cmdutil.GetDryRunFlag(cmd) {
|
if cmdutil.GetDryRunFlag(cmd) {
|
||||||
|
@ -37,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"
|
||||||
)
|
)
|
||||||
@ -45,6 +46,7 @@ import (
|
|||||||
type LabelOptions struct {
|
type LabelOptions struct {
|
||||||
// Filename options
|
// Filename options
|
||||||
resource.FilenameOptions
|
resource.FilenameOptions
|
||||||
|
RecordFlags *genericclioptions.RecordFlags
|
||||||
|
|
||||||
// Common user flags
|
// Common user flags
|
||||||
overwrite bool
|
overwrite bool
|
||||||
@ -61,6 +63,8 @@ type LabelOptions struct {
|
|||||||
newLabels map[string]string
|
newLabels map[string]string
|
||||||
removeLabels []string
|
removeLabels []string
|
||||||
|
|
||||||
|
Recorder genericclioptions.Recorder
|
||||||
|
|
||||||
// Common shared fields
|
// Common shared fields
|
||||||
out io.Writer
|
out io.Writer
|
||||||
errout io.Writer
|
errout io.Writer
|
||||||
@ -96,10 +100,19 @@ var (
|
|||||||
kubectl label pods foo bar-`))
|
kubectl label pods foo bar-`))
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCmdLabel(f cmdutil.Factory, out, errout io.Writer) *cobra.Command {
|
func NewLabelOptions(out, errOut io.Writer) *LabelOptions {
|
||||||
options := &LabelOptions{
|
return &LabelOptions{
|
||||||
errout: errout,
|
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)
|
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),
|
Long: fmt.Sprintf(labelLong, validation.LabelValueMaxLength),
|
||||||
Example: labelExample,
|
Example: labelExample,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
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()))
|
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(cmdutil.UsageErrorf(cmd, err.Error()))
|
||||||
}
|
}
|
||||||
cmdutil.CheckErr(options.RunLabel(f, cmd))
|
cmdutil.CheckErr(o.RunLabel(f, cmd))
|
||||||
},
|
},
|
||||||
ValidArgs: validArgs,
|
ValidArgs: validArgs,
|
||||||
ArgAliases: kubectl.ResourceAliases(validArgs),
|
ArgAliases: kubectl.ResourceAliases(validArgs),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
o.RecordFlags.AddFlags(cmd)
|
||||||
|
|
||||||
cmdutil.AddPrinterFlags(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(&o.overwrite, "overwrite", o.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(&o.list, "list", o.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().BoolVar(&o.local, "local", o.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().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 labels 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 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"
|
usage := "identifying the resource to update the labels"
|
||||||
cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage)
|
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||||
cmdutil.AddDryRunFlag(cmd)
|
cmdutil.AddDryRunFlag(cmd)
|
||||||
cmdutil.AddRecordFlag(cmd)
|
|
||||||
cmdutil.AddIncludeUninitializedFlag(cmd)
|
cmdutil.AddIncludeUninitializedFlag(cmd)
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 *LabelOptions) Complete(out io.Writer, cmd *cobra.Command, args []string) (err error) {
|
func (o *LabelOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||||
o.out = out
|
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.outputFormat = cmdutil.GetFlagString(cmd, "output")
|
||||||
o.dryrun = cmdutil.GetDryRunFlag(cmd)
|
o.dryrun = cmdutil.GetDryRunFlag(cmd)
|
||||||
|
|
||||||
@ -178,8 +200,6 @@ func (o *LabelOptions) RunLabel(f cmdutil.Factory, cmd *cobra.Command) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
changeCause := f.Command(cmd, false)
|
|
||||||
|
|
||||||
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
includeUninitialized := cmdutil.ShouldIncludeUninitialized(cmd, false)
|
||||||
b := f.NewBuilder().
|
b := f.NewBuilder().
|
||||||
Unstructured().
|
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 {
|
if err := labelFunc(obj, o.overwrite, o.resourceVersion, o.newLabels, o.removeLabels); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if cmdutil.ShouldRecord(cmd, info) {
|
if err := o.Recorder.Record(obj); err != nil {
|
||||||
if err := cmdutil.RecordChangeCause(obj, changeCause); err != nil {
|
glog.V(4).Infof("error recording current command: %v", err)
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
newData, err := json.Marshal(obj)
|
newData, err := json.Marshal(obj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -29,7 +29,6 @@ import (
|
|||||||
"k8s.io/client-go/rest/fake"
|
"k8s.io/client-go/rest/fake"
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/resource"
|
|
||||||
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -335,8 +334,8 @@ func TestLabelErrors(t *testing.T) {
|
|||||||
for k, v := range testCase.flags {
|
for k, v := range testCase.flags {
|
||||||
cmd.Flags().Set(k, v)
|
cmd.Flags().Set(k, v)
|
||||||
}
|
}
|
||||||
opts := LabelOptions{}
|
opts := NewLabelOptions(buf, buf)
|
||||||
err := opts.Complete(buf, cmd, testCase.args)
|
err := opts.Complete(tf, cmd, testCase.args)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = opts.Validate()
|
err = opts.Validate()
|
||||||
}
|
}
|
||||||
@ -392,9 +391,9 @@ func TestLabelForResourceFromFile(t *testing.T) {
|
|||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
cmd := NewCmdLabel(tf, buf, buf)
|
cmd := NewCmdLabel(tf, buf, buf)
|
||||||
opts := LabelOptions{FilenameOptions: resource.FilenameOptions{
|
opts := NewLabelOptions(buf, buf)
|
||||||
Filenames: []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}}}
|
opts.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
||||||
err := opts.Complete(buf, cmd, []string{"a=b"})
|
err := opts.Complete(tf, cmd, []string{"a=b"})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = opts.Validate()
|
err = opts.Validate()
|
||||||
}
|
}
|
||||||
@ -425,10 +424,10 @@ func TestLabelLocal(t *testing.T) {
|
|||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
cmd := NewCmdLabel(tf, buf, buf)
|
cmd := NewCmdLabel(tf, buf, buf)
|
||||||
opts := LabelOptions{FilenameOptions: resource.FilenameOptions{
|
opts := NewLabelOptions(buf, buf)
|
||||||
Filenames: []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}},
|
opts.Filenames = []string{"../../../test/e2e/testing-manifests/statefulset/cassandra/controller.yaml"}
|
||||||
local: true}
|
opts.local = true
|
||||||
err := opts.Complete(buf, cmd, []string{"a=b"})
|
err := opts.Complete(tf, cmd, []string{"a=b"})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = opts.Validate()
|
err = opts.Validate()
|
||||||
}
|
}
|
||||||
@ -482,9 +481,10 @@ func TestLabelMultipleObjects(t *testing.T) {
|
|||||||
tf.ClientConfigVal = defaultClientConfig()
|
tf.ClientConfigVal = defaultClientConfig()
|
||||||
|
|
||||||
buf := bytes.NewBuffer([]byte{})
|
buf := bytes.NewBuffer([]byte{})
|
||||||
opts := LabelOptions{all: true}
|
opts := NewLabelOptions(buf, buf)
|
||||||
|
opts.all = true
|
||||||
cmd := NewCmdLabel(tf, buf, buf)
|
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 {
|
if err == nil {
|
||||||
err = opts.Validate()
|
err = opts.Validate()
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,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/scheme"
|
"k8s.io/kubernetes/pkg/kubectl/scheme"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/util/i18n"
|
"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()
|
// referencing the cmd.Flags()
|
||||||
type PatchOptions struct {
|
type PatchOptions struct {
|
||||||
resource.FilenameOptions
|
resource.FilenameOptions
|
||||||
|
RecordFlags *genericclioptions.RecordFlags
|
||||||
|
|
||||||
Local bool
|
Local bool
|
||||||
DryRun bool
|
DryRun bool
|
||||||
|
|
||||||
|
Recorder genericclioptions.Recorder
|
||||||
|
|
||||||
OutputFormat string
|
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"}]'`))
|
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 {
|
func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
||||||
options := &PatchOptions{}
|
o := NewPatchOptions()
|
||||||
validArgs := cmdutil.ValidArgList(f)
|
validArgs := cmdutil.ValidArgList(f)
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
@ -90,32 +102,47 @@ func NewCmdPatch(f cmdutil.Factory, out io.Writer) *cobra.Command {
|
|||||||
Long: patchLong,
|
Long: patchLong,
|
||||||
Example: patchExample,
|
Example: patchExample,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
options.OutputFormat = cmdutil.GetFlagString(cmd, "output")
|
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||||
options.DryRun = cmdutil.GetFlagBool(cmd, "dry-run")
|
cmdutil.CheckErr(o.RunPatch(f, out, cmd, args))
|
||||||
err := RunPatch(f, out, cmd, args, options)
|
|
||||||
cmdutil.CheckErr(err)
|
|
||||||
},
|
},
|
||||||
ValidArgs: validArgs,
|
ValidArgs: validArgs,
|
||||||
ArgAliases: kubectl.ResourceAliases(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.Flags().StringP("patch", "p", "", "The patch to be applied to the resource JSON file.")
|
||||||
cmd.MarkFlagRequired("patch")
|
cmd.MarkFlagRequired("patch")
|
||||||
cmd.Flags().String("type", "strategic", fmt.Sprintf("The type of patch being provided; one of %v", sets.StringKeySet(patchTypes).List()))
|
cmd.Flags().String("type", "strategic", fmt.Sprintf("The type of patch being provided; one of %v", sets.StringKeySet(patchTypes).List()))
|
||||||
cmdutil.AddPrinterFlags(cmd)
|
cmdutil.AddPrinterFlags(cmd)
|
||||||
cmdutil.AddRecordFlag(cmd)
|
|
||||||
cmdutil.AddDryRunFlag(cmd)
|
cmdutil.AddDryRunFlag(cmd)
|
||||||
|
|
||||||
usage := "identifying the resource to update"
|
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
|
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 {
|
switch {
|
||||||
case options.Local && len(args) != 0:
|
case o.Local && len(args) != 0:
|
||||||
return fmt.Errorf("cannot specify --local and server resources")
|
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().
|
Unstructured().
|
||||||
ContinueOnError().
|
ContinueOnError().
|
||||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||||
FilenameParam(enforceNamespace, &options.FilenameOptions).
|
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||||
ResourceTypeOrNameArgs(false, args...).
|
ResourceTypeOrNameArgs(false, args...).
|
||||||
Flatten().
|
Flatten().
|
||||||
Do()
|
Do()
|
||||||
@ -169,38 +196,36 @@ func RunPatch(f cmdutil.Factory, out io.Writer, cmd *cobra.Command, args []strin
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !options.Local && !options.DryRun {
|
if !o.Local && !o.DryRun {
|
||||||
helper := resource.NewHelper(client, mapping)
|
helper := resource.NewHelper(client, mapping)
|
||||||
patchedObj, err := helper.Patch(namespace, name, patchType, patchBytes)
|
patchedObj, err := helper.Patch(namespace, name, patchType, patchBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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) {
|
didPatch := !reflect.DeepEqual(info.Object, patchedObj)
|
||||||
// Copy the resource info and update with the result of applying the user's patch
|
|
||||||
infoCopy := *info
|
// if the recorder makes a change, compute and create another patch
|
||||||
infoCopy.Object = patchedObj
|
if mergePatch, err := o.Recorder.MakeRecordMergePatch(patchedObj); err != nil {
|
||||||
if patch, patchType, err := cmdutil.ChangeResourcePatch(&infoCopy, f.Command(cmd, true)); err == nil {
|
glog.V(4).Infof("error recording current command: %v", err)
|
||||||
if recordedObj, err := helper.Patch(info.Namespace, info.Name, patchType, patch); err != nil {
|
} 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)
|
glog.V(4).Infof("error recording reason: %v", err)
|
||||||
} else {
|
} else {
|
||||||
patchedObj = recordedObj
|
patchedObj = recordedObj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
count++
|
count++
|
||||||
|
|
||||||
didPatch := !reflect.DeepEqual(info.Object, patchedObj)
|
|
||||||
|
|
||||||
// After computing whether we changed data, refresh the resource info with the resulting object
|
// After computing whether we changed data, refresh the resource info with the resulting object
|
||||||
if err := info.Refresh(patchedObj, true); err != nil {
|
if err := info.Refresh(patchedObj, true); err != nil {
|
||||||
return err
|
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)
|
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 object was not successfully patched, exit with error code 1
|
||||||
if !didPatch {
|
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)
|
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
|
return nil
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -33,6 +33,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/kubectl/validation"
|
"k8s.io/kubernetes/pkg/kubectl/validation"
|
||||||
@ -64,39 +65,43 @@ var (
|
|||||||
kubectl replace --force -f ./pod.json`))
|
kubectl replace --force -f ./pod.json`))
|
||||||
)
|
)
|
||||||
|
|
||||||
type ReplaceOpts struct {
|
type ReplaceOptions struct {
|
||||||
PrintFlags *printers.PrintFlags
|
PrintFlags *printers.PrintFlags
|
||||||
DeleteFlags *DeleteFlags
|
DeleteFlags *DeleteFlags
|
||||||
|
RecordFlags *genericclioptions.RecordFlags
|
||||||
|
|
||||||
DeleteOptions *DeleteOptions
|
DeleteOptions *DeleteOptions
|
||||||
|
|
||||||
PrintObj func(obj runtime.Object) error
|
PrintObj func(obj runtime.Object) error
|
||||||
|
|
||||||
createAnnotation bool
|
createAnnotation bool
|
||||||
changeCause string
|
|
||||||
validate bool
|
validate bool
|
||||||
|
|
||||||
Schema validation.Schema
|
Schema validation.Schema
|
||||||
Builder func() *resource.Builder
|
Builder func() *resource.Builder
|
||||||
BuilderArgs []string
|
BuilderArgs []string
|
||||||
|
|
||||||
ShouldRecord func(info *resource.Info) bool
|
|
||||||
|
|
||||||
Namespace string
|
Namespace string
|
||||||
EnforceNamespace bool
|
EnforceNamespace bool
|
||||||
|
|
||||||
|
Recorder genericclioptions.Recorder
|
||||||
|
|
||||||
Out io.Writer
|
Out io.Writer
|
||||||
ErrOut io.Writer
|
ErrOut io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCmdReplace(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
func NewReplaceOptions(out, errOut io.Writer) *ReplaceOptions {
|
||||||
options := &ReplaceOpts{
|
return &ReplaceOptions{
|
||||||
PrintFlags: printers.NewPrintFlags("replaced"),
|
PrintFlags: printers.NewPrintFlags("replaced"),
|
||||||
DeleteFlags: NewDeleteFlags("to use to replace the resource."),
|
DeleteFlags: NewDeleteFlags("to use to replace the resource."),
|
||||||
|
|
||||||
Out: out,
|
Out: out,
|
||||||
ErrOut: errOut,
|
ErrOut: errOut,
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCmdReplace(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||||
|
o := NewReplaceOptions(out, errOut)
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "replace -f FILENAME",
|
Use: "replace -f FILENAME",
|
||||||
@ -106,32 +111,35 @@ func NewCmdReplace(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
|||||||
Example: replaceExample,
|
Example: replaceExample,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
||||||
cmdutil.CheckErr(options.Complete(f, cmd, args))
|
cmdutil.CheckErr(o.Complete(f, cmd, args))
|
||||||
cmdutil.CheckErr(options.Validate(cmd))
|
cmdutil.CheckErr(o.Validate(cmd))
|
||||||
cmdutil.CheckErr(options.Run())
|
cmdutil.CheckErr(o.Run())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
options.PrintFlags.AddFlags(cmd)
|
o.PrintFlags.AddFlags(cmd)
|
||||||
options.DeleteFlags.AddFlags(cmd)
|
o.DeleteFlags.AddFlags(cmd)
|
||||||
|
o.RecordFlags.AddFlags(cmd)
|
||||||
|
|
||||||
cmd.MarkFlagRequired("filename")
|
cmd.MarkFlagRequired("filename")
|
||||||
cmdutil.AddValidateFlags(cmd)
|
cmdutil.AddValidateFlags(cmd)
|
||||||
cmdutil.AddApplyAnnotationFlags(cmd)
|
cmdutil.AddApplyAnnotationFlags(cmd)
|
||||||
cmdutil.AddRecordFlag(cmd)
|
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ReplaceOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
func (o *ReplaceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
|
||||||
o.validate = cmdutil.GetFlagBool(cmd, "validate")
|
var err error
|
||||||
o.changeCause = f.Command(cmd, false)
|
|
||||||
o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
|
|
||||||
|
|
||||||
o.ShouldRecord = func(info *resource.Info) bool {
|
o.RecordFlags.Complete(f.Command(cmd, false))
|
||||||
return cmdutil.ShouldRecord(cmd, info)
|
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()
|
printer, err := o.PrintFlags.ToPrinter()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -173,7 +181,7 @@ func (o *ReplaceOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []str
|
|||||||
return nil
|
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 {
|
if o.DeleteOptions.GracePeriod >= 0 && !o.DeleteOptions.ForceDeletion {
|
||||||
return fmt.Errorf("--grace-period must have --force specified")
|
return fmt.Errorf("--grace-period must have --force specified")
|
||||||
}
|
}
|
||||||
@ -189,7 +197,7 @@ func (o *ReplaceOpts) Validate(cmd *cobra.Command) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ReplaceOpts) Run() error {
|
func (o *ReplaceOptions) Run() error {
|
||||||
if o.DeleteOptions.ForceDeletion {
|
if o.DeleteOptions.ForceDeletion {
|
||||||
return o.forceReplace()
|
return o.forceReplace()
|
||||||
}
|
}
|
||||||
@ -215,10 +223,8 @@ func (o *ReplaceOpts) Run() error {
|
|||||||
return cmdutil.AddSourceToErr("replacing", info.Source, err)
|
return cmdutil.AddSourceToErr("replacing", info.Source, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.ShouldRecord(info) {
|
if err := o.Recorder.Record(info.Object); err != nil {
|
||||||
if err := cmdutil.RecordChangeCause(info.Object, o.changeCause); err != nil {
|
glog.V(4).Infof("error recording current command: %v", err)
|
||||||
return cmdutil.AddSourceToErr("replacing", info.Source, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize the object with the annotation applied.
|
// 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 {
|
for i, filename := range o.DeleteOptions.FilenameOptions.Filenames {
|
||||||
if filename == "-" {
|
if filename == "-" {
|
||||||
tempDir, err := ioutil.TempDir("", "kubectl_replace_")
|
tempDir, err := ioutil.TempDir("", "kubectl_replace_")
|
||||||
@ -313,10 +319,8 @@ func (o *ReplaceOpts) forceReplace() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.ShouldRecord(info) {
|
if err := o.Recorder.Record(info.Object); err != nil {
|
||||||
if err := cmdutil.RecordChangeCause(info.Object, o.changeCause); err != nil {
|
glog.V(4).Infof("error recording current command: %v", err)
|
||||||
return cmdutil.AddSourceToErr("replacing", info.Source, err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object)
|
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/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
batchclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/batch/internalversion"
|
batchclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/batch/internalversion"
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/scalejob"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/scalejob"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
@ -58,9 +61,24 @@ var (
|
|||||||
kubectl scale --replicas=3 statefulset/web`))
|
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
|
// 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 {
|
func NewCmdScale(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
||||||
options := &resource.FilenameOptions{}
|
o := NewScaleOptions()
|
||||||
|
|
||||||
validArgs := []string{"deployment", "replicaset", "replicationcontroller", "statefulset"}
|
validArgs := []string{"deployment", "replicaset", "replicationcontroller", "statefulset"}
|
||||||
argAliases := kubectl.ResourceAliases(validArgs)
|
argAliases := kubectl.ResourceAliases(validArgs)
|
||||||
@ -72,14 +90,17 @@ func NewCmdScale(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
|
|||||||
Long: scaleLong,
|
Long: scaleLong,
|
||||||
Example: scaleExample,
|
Example: scaleExample,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
cmdutil.CheckErr(o.Complete(f, cmd))
|
||||||
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
cmdutil.CheckErr(cmdutil.ValidateOutputArgs(cmd))
|
||||||
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
|
shortOutput := cmdutil.GetFlagString(cmd, "output") == "name"
|
||||||
err := RunScale(f, out, errOut, cmd, args, shortOutput, options)
|
cmdutil.CheckErr(o.RunScale(f, out, errOut, cmd, args, shortOutput))
|
||||||
cmdutil.CheckErr(err)
|
|
||||||
},
|
},
|
||||||
ValidArgs: validArgs,
|
ValidArgs: validArgs,
|
||||||
ArgAliases: argAliases,
|
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().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().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."))
|
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.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).")
|
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.AddOutputFlagsForMutation(cmd)
|
||||||
cmdutil.AddRecordFlag(cmd)
|
|
||||||
|
|
||||||
usage := "identifying the resource to set a new size"
|
usage := "identifying the resource to set a new size"
|
||||||
cmdutil.AddFilenameOptionFlags(cmd, options, usage)
|
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
|
||||||
return cmd
|
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
|
// 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()
|
cmdNamespace, enforceNamespace, err := f.DefaultNamespace()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -114,7 +146,7 @@ func RunScale(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args
|
|||||||
Unstructured().
|
Unstructured().
|
||||||
ContinueOnError().
|
ContinueOnError().
|
||||||
NamespaceParam(cmdNamespace).DefaultNamespace().
|
NamespaceParam(cmdNamespace).DefaultNamespace().
|
||||||
FilenameParam(enforceNamespace, options).
|
FilenameParam(enforceNamespace, &o.FilenameOptions).
|
||||||
ResourceTypeOrNameArgs(all, args...).
|
ResourceTypeOrNameArgs(all, args...).
|
||||||
Flatten().
|
Flatten().
|
||||||
LabelSelectorParam(selector).
|
LabelSelectorParam(selector).
|
||||||
@ -180,22 +212,20 @@ func RunScale(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cmdutil.ShouldRecord(cmd, info) {
|
// if the recorder makes a change, compute and create another patch
|
||||||
patchBytes, patchType, err := cmdutil.ChangeResourcePatch(info, f.Command(cmd, true))
|
if mergePatch, err := o.Recorder.MakeRecordMergePatch(info.Object); err != nil {
|
||||||
if err != nil {
|
glog.V(4).Infof("error recording current command: %v", err)
|
||||||
return err
|
} else if len(mergePatch) > 0 {
|
||||||
}
|
|
||||||
mapping := info.ResourceMapping()
|
|
||||||
client, err := f.UnstructuredClientForMapping(mapping)
|
client, err := f.UnstructuredClientForMapping(mapping)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
helper := resource.NewHelper(client, mapping)
|
helper := resource.NewHelper(client, mapping)
|
||||||
_, err = helper.Patch(info.Namespace, info.Name, patchType, patchBytes)
|
if _, err := helper.Patch(info.Namespace, info.Name, types.MergePatchType, mergePatch); err != nil {
|
||||||
if err != nil {
|
glog.V(4).Infof("error recording reason: %v", err)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
counter++
|
counter++
|
||||||
cmdutil.PrintSuccess(shortOutput, out, info.Object, false, "scaled")
|
cmdutil.PrintSuccess(shortOutput, out, info.Object, false, "scaled")
|
||||||
return nil
|
return nil
|
||||||
|
@ -122,8 +122,6 @@ type EnvOptions struct {
|
|||||||
Builder *resource.Builder
|
Builder *resource.Builder
|
||||||
Infos []*resource.Info
|
Infos []*resource.Info
|
||||||
|
|
||||||
Cmd *cobra.Command
|
|
||||||
|
|
||||||
UpdatePodSpecForObject func(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error)
|
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)
|
resources, envArgs, ok := envutil.SplitEnvironmentFromResources(args)
|
||||||
if !ok {
|
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 {
|
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>")
|
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.EnvArgs = envArgs
|
||||||
o.Resources = resources
|
o.Resources = resources
|
||||||
o.Cmd = cmd
|
|
||||||
|
|
||||||
if o.DryRun {
|
if o.DryRun {
|
||||||
// TODO(juanvallejo): This can be cleaned up even further by creating
|
// 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
|
o.PrintObj = printer.PrintObj
|
||||||
|
|
||||||
if o.List && len(o.Output) > 0 {
|
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
|
return nil
|
||||||
|
@ -50,9 +50,7 @@ type SetImageOptions struct {
|
|||||||
DryRun bool
|
DryRun bool
|
||||||
All bool
|
All bool
|
||||||
Output string
|
Output string
|
||||||
ChangeCause string
|
|
||||||
Local bool
|
Local bool
|
||||||
Cmd *cobra.Command
|
|
||||||
ResolveImage func(in string) (string, error)
|
ResolveImage func(in string) (string, error)
|
||||||
|
|
||||||
PrintObj printers.ResourcePrinterFunc
|
PrintObj printers.ResourcePrinterFunc
|
||||||
@ -138,11 +136,9 @@ func (o *SetImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
|
|||||||
}
|
}
|
||||||
|
|
||||||
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
|
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
|
||||||
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")
|
||||||
o.ResolveImage = f.ResolveImage
|
o.ResolveImage = f.ResolveImage
|
||||||
o.Cmd = cmd
|
|
||||||
|
|
||||||
if o.DryRun {
|
if o.DryRun {
|
||||||
o.PrintFlags.Complete("%s (dry run)")
|
o.PrintFlags.Complete("%s (dry run)")
|
||||||
|
@ -75,9 +75,7 @@ type SetResourcesOptions struct {
|
|||||||
ContainerSelector string
|
ContainerSelector string
|
||||||
Output string
|
Output string
|
||||||
All bool
|
All bool
|
||||||
ChangeCause string
|
|
||||||
Local bool
|
Local bool
|
||||||
Cmd *cobra.Command
|
|
||||||
|
|
||||||
DryRun bool
|
DryRun bool
|
||||||
|
|
||||||
@ -157,9 +155,7 @@ func (o *SetResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, ar
|
|||||||
|
|
||||||
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
|
o.UpdatePodSpecForObject = f.UpdatePodSpecForObject
|
||||||
o.Output = cmdutil.GetFlagString(cmd, "output")
|
o.Output = cmdutil.GetFlagString(cmd, "output")
|
||||||
o.ChangeCause = f.Command(cmd, false)
|
o.DryRun = cmdutil.GetDryRunFlag(cmd)
|
||||||
o.Cmd = cmd
|
|
||||||
o.DryRun = cmdutil.GetDryRunFlag(o.Cmd)
|
|
||||||
|
|
||||||
if o.DryRun {
|
if o.DryRun {
|
||||||
o.PrintFlags.Complete("%s (dry run)")
|
o.PrintFlags.Complete("%s (dry run)")
|
||||||
|
@ -48,8 +48,6 @@ type SetSelectorOptions struct {
|
|||||||
local bool
|
local bool
|
||||||
dryrun bool
|
dryrun bool
|
||||||
all bool
|
all bool
|
||||||
record bool
|
|
||||||
changeCause string
|
|
||||||
output string
|
output string
|
||||||
|
|
||||||
resources []string
|
resources []string
|
||||||
@ -141,7 +139,6 @@ func (o *SetSelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
o.changeCause = f.Command(cmd, false)
|
|
||||||
mapper, _ := f.Object()
|
mapper, _ := f.Object()
|
||||||
o.mapper = mapper
|
o.mapper = mapper
|
||||||
|
|
||||||
|
@ -65,12 +65,9 @@ type SetServiceAccountOptions struct {
|
|||||||
out io.Writer
|
out io.Writer
|
||||||
err io.Writer
|
err io.Writer
|
||||||
dryRun bool
|
dryRun bool
|
||||||
cmd *cobra.Command
|
|
||||||
shortOutput bool
|
shortOutput bool
|
||||||
all bool
|
all bool
|
||||||
record bool
|
|
||||||
output string
|
output string
|
||||||
changeCause string
|
|
||||||
local bool
|
local bool
|
||||||
updatePodSpecForObject func(runtime.Object, func(*v1.PodSpec) error) (bool, error)
|
updatePodSpecForObject func(runtime.Object, func(*v1.PodSpec) error) (bool, error)
|
||||||
infos []*resource.Info
|
infos []*resource.Info
|
||||||
@ -132,12 +129,9 @@ func (o *SetServiceAccountOptions) Complete(f cmdutil.Factory, cmd *cobra.Comman
|
|||||||
}
|
}
|
||||||
|
|
||||||
o.shortOutput = cmdutil.GetFlagString(cmd, "output") == "name"
|
o.shortOutput = cmdutil.GetFlagString(cmd, "output") == "name"
|
||||||
o.record = cmdutil.GetRecordFlag(cmd)
|
|
||||||
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")
|
||||||
o.updatePodSpecForObject = f.UpdatePodSpecForObject
|
o.updatePodSpecForObject = f.UpdatePodSpecForObject
|
||||||
o.cmd = cmd
|
|
||||||
|
|
||||||
if o.dryRun {
|
if o.dryRun {
|
||||||
o.PrintFlags.Complete("%s (dry run)")
|
o.PrintFlags.Complete("%s (dry run)")
|
||||||
|
@ -58,11 +58,8 @@ go_library(
|
|||||||
"//vendor/k8s.io/apimachinery/pkg/labels:go_default_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:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime/schema: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/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/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/util/yaml:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/version:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/watch:go_default_library",
|
||||||
|
@ -34,13 +34,9 @@ import (
|
|||||||
kerrors "k8s.io/apimachinery/pkg/api/errors"
|
kerrors "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"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/types"
|
|
||||||
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
utilerrors "k8s.io/apimachinery/pkg/util/errors"
|
||||||
"k8s.io/apimachinery/pkg/util/json"
|
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/strategicpatch"
|
|
||||||
"k8s.io/apimachinery/pkg/util/yaml"
|
"k8s.io/apimachinery/pkg/util/yaml"
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
"k8s.io/kubernetes/pkg/kubectl"
|
"k8s.io/kubernetes/pkg/kubectl"
|
||||||
@ -517,64 +513,10 @@ func UpdateObject(info *resource.Info, codec runtime.Codec, updateFn func(runtim
|
|||||||
return info.Object, nil
|
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 {
|
func GetDryRunFlag(cmd *cobra.Command) bool {
|
||||||
return GetFlagBool(cmd, "dry-run")
|
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.
|
// ContainsChangeCause checks if input resource info contains change-cause annotation.
|
||||||
func ContainsChangeCause(info *resource.Info) bool {
|
func ContainsChangeCause(info *resource.Info) bool {
|
||||||
annotations, err := info.Mapping.MetadataAccessor.Annotations(info.Object)
|
annotations, err := info.Mapping.MetadataAccessor.Annotations(info.Object)
|
||||||
@ -584,11 +526,6 @@ func ContainsChangeCause(info *resource.Info) bool {
|
|||||||
return len(annotations[kubectl.ChangeCauseAnnotation]) > 0
|
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
|
// 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) {
|
func GetResourcesAndPairs(args []string, pairType string) (resources []string, pairArgs []string, err error) {
|
||||||
foundPair := false
|
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
|
// 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
|
// 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.
|
// fail and we will manually drop all comments from the file.
|
||||||
|
@ -19,7 +19,6 @@ package util
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"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 {
|
type checkErrTestCase struct {
|
||||||
err error
|
err error
|
||||||
expectedErr string
|
expectedErr string
|
||||||
|
@ -9,9 +9,11 @@ go_library(
|
|||||||
importpath = "k8s.io/kubernetes/pkg/kubectl/genericclioptions",
|
importpath = "k8s.io/kubernetes/pkg/kubectl/genericclioptions",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//vendor/github.com/evanphx/json-patch:go_default_library",
|
||||||
"//vendor/github.com/spf13/cobra: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/api/meta:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/runtime: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
|
package genericclioptions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/evanphx/json-patch"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/meta"
|
"k8s.io/apimachinery/pkg/api/meta"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
"k8s.io/apimachinery/pkg/util/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ChangeCauseAnnotation is the annotation indicating a guess at "why" something was changed
|
// ChangeCauseAnnotation is the annotation indicating a guess at "why" something was changed
|
||||||
@ -92,6 +94,7 @@ func NewRecordFlags() *RecordFlags {
|
|||||||
type Recorder interface {
|
type Recorder interface {
|
||||||
// Record records why a runtime.Object was changed in an annotation.
|
// Record records why a runtime.Object was changed in an annotation.
|
||||||
Record(runtime.Object) error
|
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.
|
// 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
|
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
|
// ChangeCauseRecorder annotates a "change-cause" to an input runtime object
|
||||||
type ChangeCauseRecorder struct {
|
type ChangeCauseRecorder struct {
|
||||||
changeCause string
|
changeCause string
|
||||||
@ -122,3 +130,23 @@ func (r *ChangeCauseRecorder) Record(obj runtime.Object) error {
|
|||||||
accessor.SetAnnotations(annotations)
|
accessor.SetAnnotations(annotations)
|
||||||
return nil
|
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
Block a user