Merge pull request #88292 from julianvmodesto/add-dry-run

Add --dry-run=server|client|none to more kubectl commands

Kubernetes-commit: 1591590030bc60b0dc877efb5d5e67e4791b40b8
This commit is contained in:
Kubernetes Publisher 2020-02-20 16:30:25 -08:00
commit c131bf61bf
7 changed files with 148 additions and 16 deletions

2
Godeps/Godeps.json generated
View File

@ -580,7 +580,7 @@
}, },
{ {
"ImportPath": "k8s.io/client-go", "ImportPath": "k8s.io/client-go",
"Rev": "cb2a0501818e" "Rev": "5e1786105b6f"
}, },
{ {
"ImportPath": "k8s.io/code-generator", "ImportPath": "k8s.io/code-generator",

4
go.mod
View File

@ -39,7 +39,7 @@ require (
k8s.io/api v0.0.0-20200214081624-026463abc787 k8s.io/api v0.0.0-20200214081624-026463abc787
k8s.io/apimachinery v0.0.0-20200214081019-2373d029717c k8s.io/apimachinery v0.0.0-20200214081019-2373d029717c
k8s.io/cli-runtime v0.0.0-20200221172330-03707b9714f9 k8s.io/cli-runtime v0.0.0-20200221172330-03707b9714f9
k8s.io/client-go v0.0.0-20200221163114-cb2a0501818e k8s.io/client-go v0.0.0-20200221163115-5e1786105b6f
k8s.io/component-base v0.0.0-20200221165142-d6212a66f6f6 k8s.io/component-base v0.0.0-20200221165142-d6212a66f6f6
k8s.io/klog v1.0.0 k8s.io/klog v1.0.0
k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c k8s.io/kube-openapi v0.0.0-20200121204235-bf4fb3bd569c
@ -56,7 +56,7 @@ replace (
k8s.io/api => k8s.io/api v0.0.0-20200214081624-026463abc787 k8s.io/api => k8s.io/api v0.0.0-20200214081624-026463abc787
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20200214081019-2373d029717c k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20200214081019-2373d029717c
k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20200221172330-03707b9714f9 k8s.io/cli-runtime => k8s.io/cli-runtime v0.0.0-20200221172330-03707b9714f9
k8s.io/client-go => k8s.io/client-go v0.0.0-20200221163114-cb2a0501818e k8s.io/client-go => k8s.io/client-go v0.0.0-20200221163115-5e1786105b6f
k8s.io/code-generator => k8s.io/code-generator v0.0.0-20200214080538-dc8f3adce97c k8s.io/code-generator => k8s.io/code-generator v0.0.0-20200214080538-dc8f3adce97c
k8s.io/component-base => k8s.io/component-base v0.0.0-20200221165142-d6212a66f6f6 k8s.io/component-base => k8s.io/component-base v0.0.0-20200221165142-d6212a66f6f6
k8s.io/metrics => k8s.io/metrics v0.0.0-20200221172033-647dd8d4af75 k8s.io/metrics => k8s.io/metrics v0.0.0-20200221172033-647dd8d4af75

2
go.sum
View File

@ -301,7 +301,7 @@ honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWh
k8s.io/api v0.0.0-20200214081624-026463abc787/go.mod h1:brPp6rLV9ZWi2IgXmvCsY7TKw2l27eF4rfCHlyW88ys= k8s.io/api v0.0.0-20200214081624-026463abc787/go.mod h1:brPp6rLV9ZWi2IgXmvCsY7TKw2l27eF4rfCHlyW88ys=
k8s.io/apimachinery v0.0.0-20200214081019-2373d029717c/go.mod h1:5X8oEhnd931nEg6/Nkumo00nT6ZsCLp2h7Xwd7Ym6P4= k8s.io/apimachinery v0.0.0-20200214081019-2373d029717c/go.mod h1:5X8oEhnd931nEg6/Nkumo00nT6ZsCLp2h7Xwd7Ym6P4=
k8s.io/cli-runtime v0.0.0-20200221172330-03707b9714f9/go.mod h1:jFVnu9CV5hIeRRksJ7Tt7Uo+k7nXrLmHlLDSZT+lSsw= k8s.io/cli-runtime v0.0.0-20200221172330-03707b9714f9/go.mod h1:jFVnu9CV5hIeRRksJ7Tt7Uo+k7nXrLmHlLDSZT+lSsw=
k8s.io/client-go v0.0.0-20200221163114-cb2a0501818e/go.mod h1:UmUmKsm/QPFM6PX++FkaGSN2sbquEn4rxsBMAvnX+58= k8s.io/client-go v0.0.0-20200221163115-5e1786105b6f/go.mod h1:UmUmKsm/QPFM6PX++FkaGSN2sbquEn4rxsBMAvnX+58=
k8s.io/code-generator v0.0.0-20200214080538-dc8f3adce97c/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc= k8s.io/code-generator v0.0.0-20200214080538-dc8f3adce97c/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRVkTc=
k8s.io/component-base v0.0.0-20200221165142-d6212a66f6f6/go.mod h1:B8q2AK86xxE1I0R1+CrykxCmsXybANtr7pvlzNE9vjo= k8s.io/component-base v0.0.0-20200221165142-d6212a66f6f6/go.mod h1:B8q2AK86xxE1I0R1+CrykxCmsXybANtr7pvlzNE9vjo=
k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=

View File

@ -115,6 +115,9 @@ type DeleteOptions struct {
GracePeriod int GracePeriod int
Timeout time.Duration Timeout time.Duration
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.DryRunVerifier
Output string Output string
DynamicClient dynamic.Interface DynamicClient dynamic.Interface
@ -143,6 +146,7 @@ func NewCmdDelete(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra
} }
deleteFlags.AddFlags(cmd) deleteFlags.AddFlags(cmd)
cmdutil.AddDryRunFlag(cmd)
return cmd return cmd
} }
@ -173,6 +177,20 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Co
o.GracePeriod = 1 o.GracePeriod = 1
} }
o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd)
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
discoveryClient, err := f.ToDiscoveryClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient)
if len(o.Raw) == 0 { if len(o.Raw) == 0 {
r := f.NewBuilder(). r := f.NewBuilder().
Unstructured(). Unstructured().
@ -291,6 +309,18 @@ func (o *DeleteOptions) DeleteResult(r *resource.Result) error {
fmt.Fprintf(o.ErrOut, "warning: deleting cluster-scoped resources, not scoped to the provided namespace\n") fmt.Fprintf(o.ErrOut, "warning: deleting cluster-scoped resources, not scoped to the provided namespace\n")
warnClusterScope = false warnClusterScope = false
} }
if o.DryRunStrategy == cmdutil.DryRunClient {
if !o.Quiet {
o.PrintObj(info)
}
return nil
}
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
return err
}
}
response, err := o.deleteResource(info, options) response, err := o.deleteResource(info, options)
if err != nil { if err != nil {
return err return err
@ -330,6 +360,11 @@ func (o *DeleteOptions) DeleteResult(r *resource.Result) error {
return nil return nil
} }
// If we are dry-running, then we don't want to wait
if o.DryRunStrategy != cmdutil.DryRunNone {
return nil
}
effectiveTimeout := o.Timeout effectiveTimeout := o.Timeout
if effectiveTimeout == 0 { if effectiveTimeout == 0 {
// if we requested to wait forever, set it to a week. // if we requested to wait forever, set it to a week.
@ -356,7 +391,10 @@ func (o *DeleteOptions) DeleteResult(r *resource.Result) error {
} }
func (o *DeleteOptions) deleteResource(info *resource.Info, deleteOptions *metav1.DeleteOptions) (runtime.Object, error) { func (o *DeleteOptions) deleteResource(info *resource.Info, deleteOptions *metav1.DeleteOptions) (runtime.Object, error) {
deleteResponse, err := resource.NewHelper(info.Client, info.Mapping).DeleteWithOptions(info.Namespace, info.Name, deleteOptions) deleteResponse, err := resource.
NewHelper(info.Client, info.Mapping).
DryRun(o.DryRunStrategy == cmdutil.DryRunServer).
DeleteWithOptions(info.Namespace, info.Name, deleteOptions)
if err != nil { if err != nil {
return nil, cmdutil.AddSourceToErr("deleting", info.Source, err) return nil, cmdutil.AddSourceToErr("deleting", info.Source, err)
} }
@ -381,6 +419,13 @@ func (o *DeleteOptions) PrintObj(info *resource.Info) {
operation = "force deleted" operation = "force deleted"
} }
switch o.DryRunStrategy {
case cmdutil.DryRunClient:
operation = fmt.Sprintf("%s (dry run)", operation)
case cmdutil.DryRunServer:
operation = fmt.Sprintf("%s (server dry run)", operation)
}
if o.Output == "name" { if o.Output == "name" {
// -o name: prints resource/name // -o name: prints resource/name
fmt.Fprintf(o.Out, "%s/%s\n", kindString, info.Name) fmt.Fprintf(o.Out, "%s/%s\n", kindString, info.Name)

View File

@ -33,6 +33,7 @@ import (
"k8s.io/cli-runtime/pkg/resource" "k8s.io/cli-runtime/pkg/resource"
"k8s.io/client-go/rest/fake" "k8s.io/client-go/rest/fake"
cmdtesting "k8s.io/kubectl/pkg/cmd/testing" cmdtesting "k8s.io/kubectl/pkg/cmd/testing"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme" "k8s.io/kubectl/pkg/scheme"
) )
@ -42,6 +43,7 @@ func fakecmd() *cobra.Command {
DisableFlagsInUseLine: true, DisableFlagsInUseLine: true,
Run: func(cmd *cobra.Command, args []string) {}, Run: func(cmd *cobra.Command, args []string) {},
} }
cmdutil.AddDryRunFlag(cmd)
return cmd return cmd
} }

View File

@ -74,6 +74,9 @@ type ReplaceOptions struct {
DeleteFlags *delete.DeleteFlags DeleteFlags *delete.DeleteFlags
DeleteOptions *delete.DeleteOptions DeleteOptions *delete.DeleteOptions
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.DryRunVerifier
PrintObj func(obj runtime.Object) error PrintObj func(obj runtime.Object) error
createAnnotation bool createAnnotation bool
@ -123,6 +126,7 @@ func NewCmdReplace(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobr
cmdutil.AddValidateFlags(cmd) cmdutil.AddValidateFlags(cmd)
cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddApplyAnnotationFlags(cmd)
cmdutil.AddDryRunFlag(cmd)
cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to PUT to the server. Uses the transport specified by the kubeconfig file.") cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to PUT to the server. Uses the transport specified by the kubeconfig file.")
@ -141,6 +145,21 @@ func (o *ReplaceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
o.validate = cmdutil.GetFlagBool(cmd, "validate") o.validate = cmdutil.GetFlagBool(cmd, "validate")
o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd)
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
discoveryClient, err := f.ToDiscoveryClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient)
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
printer, err := o.PrintFlags.ToPrinter() printer, err := o.PrintFlags.ToPrinter()
if err != nil { if err != nil {
return err return err
@ -149,10 +168,6 @@ func (o *ReplaceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
return printer.PrintObj(obj, o.Out) return printer.PrintObj(obj, o.Out)
} }
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
deleteOpts := o.DeleteFlags.ToOptions(dynamicClient, o.IOStreams) deleteOpts := o.DeleteFlags.ToOptions(dynamicClient, o.IOStreams)
//Replace will create a resource if it doesn't exist already, so ignore not found error //Replace will create a resource if it doesn't exist already, so ignore not found error
@ -264,8 +279,20 @@ func (o *ReplaceOptions) Run(f cmdutil.Factory) error {
klog.V(4).Infof("error recording current command: %v", err) klog.V(4).Infof("error recording current command: %v", err)
} }
if o.DryRunStrategy == cmdutil.DryRunClient {
return o.PrintObj(info.Object)
}
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
return err
}
}
// Serialize the object with the annotation applied. // Serialize the object with the annotation applied.
obj, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, true, info.Object) obj, err := resource.
NewHelper(info.Client, info.Mapping).
DryRun(o.DryRunStrategy == cmdutil.DryRunServer).
Replace(info.Namespace, info.Name, true, info.Object)
if err != nil { if err != nil {
return cmdutil.AddSourceToErr("replacing", info.Source, err) return cmdutil.AddSourceToErr("replacing", info.Source, err)
} }

View File

@ -24,8 +24,9 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/klog" "k8s.io/klog"
"k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/strategicpatch" "k8s.io/apimachinery/pkg/util/strategicpatch"
@ -44,6 +45,9 @@ type TaintOptions struct {
PrintFlags *genericclioptions.PrintFlags PrintFlags *genericclioptions.PrintFlags
ToPrinter func(string) (printers.ResourcePrinter, error) ToPrinter func(string) (printers.ResourcePrinter, error)
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.DryRunVerifier
resources []string resources []string
taintsToAdd []v1.Taint taintsToAdd []v1.Taint
taintsToRemove []v1.Taint taintsToRemove []v1.Taint
@ -109,6 +113,7 @@ func NewCmdTaint(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.
} }
options.PrintFlags.AddFlags(cmd) options.PrintFlags.AddFlags(cmd)
cmdutil.AddDryRunFlag(cmd)
cmdutil.AddValidateFlags(cmd) cmdutil.AddValidateFlags(cmd)
cmd.Flags().StringVarP(&options.selector, "selector", "l", options.selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)") cmd.Flags().StringVarP(&options.selector, "selector", "l", options.selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)")
@ -124,6 +129,21 @@ func (o *TaintOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
return err return err
} }
o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd)
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
discoveryClient, err := f.ToDiscoveryClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient)
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
// retrieves resource and taint args from args // retrieves resource and taint args from args
// also checks args to verify that all resources are specified before taints // also checks args to verify that all resources are specified before taints
taintArgs := []string{} taintArgs := []string{}
@ -261,12 +281,54 @@ func (o TaintOptions) RunTaint() error {
klog.V(2).Infof("couldn't compute patch: %v", err) klog.V(2).Infof("couldn't compute patch: %v", err)
} }
printer, err := o.ToPrinter(operation)
if err != nil {
return err
}
if o.DryRunStrategy == cmdutil.DryRunClient {
if createdPatch {
typedObj, err := scheme.Scheme.ConvertToVersion(info.Object, info.Mapping.GroupVersionKind.GroupVersion())
if err != nil {
return err
}
nodeObj, ok := typedObj.(*v1.Node)
if !ok {
return fmt.Errorf("unexpected type %T", typedObj)
}
originalObjJS, err := json.Marshal(nodeObj)
if err != nil {
return err
}
originalPatchedObjJS, err := strategicpatch.StrategicMergePatch(originalObjJS, patchBytes, nodeObj)
if err != nil {
return err
}
targetObj, err := runtime.Decode(unstructured.UnstructuredJSONScheme, originalPatchedObjJS)
if err != nil {
return err
}
return printer.PrintObj(targetObj, o.Out)
}
return printer.PrintObj(obj, o.Out)
}
mapping := info.ResourceMapping() mapping := info.ResourceMapping()
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(mapping.GroupVersionKind); err != nil {
return err
}
}
client, err := o.ClientForMapping(mapping) client, err := o.ClientForMapping(mapping)
if err != nil { if err != nil {
return err return err
} }
helper := resource.NewHelper(client, mapping) helper := resource.
NewHelper(client, mapping).
DryRun(o.DryRunStrategy == cmdutil.DryRunServer)
var outputObj runtime.Object var outputObj runtime.Object
if createdPatch { if createdPatch {
@ -278,10 +340,6 @@ func (o TaintOptions) RunTaint() error {
return err return err
} }
printer, err := o.ToPrinter(operation)
if err != nil {
return err
}
return printer.PrintObj(outputObj, o.Out) return printer.PrintObj(outputObj, o.Out)
}) })
} }