Extend --dry-run to support string values.

* Extend --dry-run to support string values for dry run strategies
  'client', 'server', and 'none'
* Ensure --dry-run is set and accessed via cmdutil
* Deprecate --dry-run (unset), --dry-run=true, and --dry-run=false

Kubernetes-commit: af52beda260257e81cc9e19e9e5108b682ee93d6
This commit is contained in:
Julian V. Modesto 2019-12-15 18:29:27 -05:00 committed by Kubernetes Publisher
parent 0dd665ea25
commit c0b11fa131
22 changed files with 95 additions and 27 deletions

View File

@ -164,7 +164,7 @@ func (o *AnnotateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
} }
o.outputFormat = cmdutil.GetFlagString(cmd, "output") o.outputFormat = cmdutil.GetFlagString(cmd, "output")
o.dryrun = cmdutil.GetDryRunFlag(cmd) o.dryrun = cmdutil.GetClientSideDryRun(cmd)
if o.dryrun { if o.dryrun {
o.PrintFlags.Complete("%s (dry run)") o.PrintFlags.Complete("%s (dry run)")

View File

@ -192,8 +192,9 @@ func NewCmdApply(baseName string, f cmdutil.Factory, ioStreams genericclioptions
cmd.Flags().BoolVar(&o.All, "all", o.All, "Select all resources in the namespace of the specified resource types.") cmd.Flags().BoolVar(&o.All, "all", o.All, "Select all resources in the namespace of the specified resource types.")
cmd.Flags().StringArrayVar(&o.PruneWhitelist, "prune-whitelist", o.PruneWhitelist, "Overwrite the default whitelist with <group/version/kind> for --prune") cmd.Flags().StringArrayVar(&o.PruneWhitelist, "prune-whitelist", o.PruneWhitelist, "Overwrite the default whitelist with <group/version/kind> for --prune")
cmd.Flags().BoolVar(&o.OpenAPIPatch, "openapi-patch", o.OpenAPIPatch, "If true, use openapi to calculate diff when the openapi presents and the resource can be found in the openapi spec. Otherwise, fall back to use baked-in types.") cmd.Flags().BoolVar(&o.OpenAPIPatch, "openapi-patch", o.OpenAPIPatch, "If true, use openapi to calculate diff when the openapi presents and the resource can be found in the openapi spec. Otherwise, fall back to use baked-in types.")
cmd.Flags().BoolVar(&o.ServerDryRun, "server-dry-run", o.ServerDryRun, "If true, request will be sent to server with dry-run flag, which means the modifications won't be persisted. This is an alpha feature and flag.") cmd.Flags().BoolVar(&o.ServerDryRun, "server-dry-run", o.ServerDryRun, "If true, request will be sent to server with dry-run flag, which means the modifications won't be persisted.")
cmd.Flags().Bool("dry-run", false, "If true, only print the object that would be sent, without sending it. Warning: --dry-run cannot accurately output the result of merging the local manifest and the server-side data. Use --server-dry-run to get the merged result instead.") cmd.Flags().MarkDeprecated("server-dry-run", "--server-dry-run is deprecated and can be replaced with --dry-run=server.")
cmdutil.AddDryRunFlag(cmd)
cmdutil.AddServerSideApplyFlags(cmd) cmdutil.AddServerSideApplyFlags(cmd)
// apply subcommands // apply subcommands
@ -210,7 +211,7 @@ func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
o.ServerSideApply = cmdutil.GetServerSideApplyFlag(cmd) o.ServerSideApply = cmdutil.GetServerSideApplyFlag(cmd)
o.ForceConflicts = cmdutil.GetForceConflictsFlag(cmd) o.ForceConflicts = cmdutil.GetForceConflictsFlag(cmd)
o.FieldManager = cmdutil.GetFieldManagerFlag(cmd) o.FieldManager = cmdutil.GetFieldManagerFlag(cmd)
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetClientSideDryRun(cmd)
o.DynamicClient, err = f.DynamicClient() o.DynamicClient, err = f.DynamicClient()
if err != nil { if err != nil {
return err return err

View File

@ -118,7 +118,7 @@ func NewCmdApplySetLastApplied(f cmdutil.Factory, ioStreams genericclioptions.IO
// Complete populates dry-run and output flag options. // Complete populates dry-run and output flag options.
func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
o.dryRun = cmdutil.GetDryRunFlag(cmd) o.dryRun = cmdutil.GetClientSideDryRun(cmd)
o.output = cmdutil.GetFlagString(cmd, "output") o.output = cmdutil.GetFlagString(cmd, "output")
o.shortOutput = o.output == "name" o.shortOutput = o.output == "name"

View File

@ -134,7 +134,7 @@ func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *
// Complete verifies command line arguments and loads data from the command environment // Complete verifies command line arguments and loads data from the command environment
func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
var err error var err error
o.dryRun = cmdutil.GetFlagBool(cmd, "dry-run") o.dryRun = cmdutil.GetClientSideDryRun(cmd)
o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
o.builder = f.NewBuilder() o.builder = f.NewBuilder()
discoveryClient, err := f.ToDiscoveryClient() discoveryClient, err := f.ToDiscoveryClient()

View File

@ -191,7 +191,7 @@ func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
return err return err
} }
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetClientSideDryRun(cmd)
if o.DryRun { if o.DryRun {
o.PrintFlags.Complete("%s (dry run)") o.PrintFlags.Complete("%s (dry run)")
@ -360,7 +360,7 @@ func (o *CreateSubcommandOptions) Complete(f cmdutil.Factory, cmd *cobra.Command
o.Name = name o.Name = name
o.StructuredGenerator = generator o.StructuredGenerator = generator
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetClientSideDryRun(cmd)
o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
if o.DryRun { if o.DryRun {

View File

@ -133,7 +133,7 @@ func (o *CreateCronJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, a
o.Builder = f.NewBuilder() o.Builder = f.NewBuilder()
o.Cmd = cmd o.Cmd = cmd
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetClientSideDryRun(cmd)
if o.DryRun { if o.DryRun {
o.PrintFlags.Complete("%s (dry run)") o.PrintFlags.Complete("%s (dry run)")
} }

View File

@ -132,7 +132,7 @@ func (o *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
o.Builder = f.NewBuilder() o.Builder = f.NewBuilder()
o.Cmd = cmd o.Cmd = cmd
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetClientSideDryRun(cmd)
if o.DryRun { if o.DryRun {
o.PrintFlags.Complete("%s (dry run)") o.PrintFlags.Complete("%s (dry run)")
} }

View File

@ -235,7 +235,7 @@ func (o *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
return err return err
} }
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetClientSideDryRun(cmd)
o.OutputFormat = cmdutil.GetFlagString(cmd, "output") o.OutputFormat = cmdutil.GetFlagString(cmd, "output")
if o.DryRun { if o.DryRun {

View File

@ -211,7 +211,7 @@ func (o *DrainCmdOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
return cmdutil.UsageErrorf(cmd, "error: cannot specify both a node name and a --selector option") return cmdutil.UsageErrorf(cmd, "error: cannot specify both a node name and a --selector option")
} }
o.drainer.DryRun = cmdutil.GetDryRunFlag(cmd) o.drainer.DryRun = cmdutil.GetClientSideDryRun(cmd)
if o.drainer.Client, err = f.KubernetesClientSet(); err != nil { if o.drainer.Client, err = f.KubernetesClientSet(); err != nil {
return err return err

View File

@ -167,7 +167,7 @@ func NewCmdExposeService(f cmdutil.Factory, streams genericclioptions.IOStreams)
} }
func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetClientSideDryRun(cmd)
if o.DryRun { if o.DryRun {
o.PrintFlags.Complete("%s (dry run)") o.PrintFlags.Complete("%s (dry run)")

View File

@ -164,7 +164,7 @@ func (o *LabelOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
} }
o.outputFormat = cmdutil.GetFlagString(cmd, "output") o.outputFormat = cmdutil.GetFlagString(cmd, "output")
o.dryrun = cmdutil.GetDryRunFlag(cmd) o.dryrun = cmdutil.GetClientSideDryRun(cmd)
o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) { o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
o.PrintFlags.NamePrintFlags.Operation = operation o.PrintFlags.NamePrintFlags.Operation = operation

View File

@ -139,7 +139,7 @@ func (o *PatchOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st
} }
o.outputFormat = cmdutil.GetFlagString(cmd, "output") o.outputFormat = cmdutil.GetFlagString(cmd, "output")
o.dryRun = cmdutil.GetFlagBool(cmd, "dry-run") o.dryRun = cmdutil.GetClientSideDryRun(cmd)
o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) { o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) {
o.PrintFlags.NamePrintFlags.Operation = operation o.PrintFlags.NamePrintFlags.Operation = operation

View File

@ -195,7 +195,7 @@ func (o *RollingUpdateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, a
if len(args) > 0 { if len(args) > 0 {
o.OldName = args[0] o.OldName = args[0]
} }
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetClientSideDryRun(cmd)
o.OutputFormat = cmdutil.GetFlagString(cmd, "output") o.OutputFormat = cmdutil.GetFlagString(cmd, "output")
o.KeepOldName = len(args) == 1 o.KeepOldName = len(args) == 1
o.ShouldValidate = cmdutil.GetFlagBool(cmd, "validate") o.ShouldValidate = cmdutil.GetFlagBool(cmd, "validate")

View File

@ -104,7 +104,7 @@ func NewCmdRolloutUndo(f cmdutil.Factory, streams genericclioptions.IOStreams) *
// Complete completes al the required options // Complete completes al the required options
func (o *UndoOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { func (o *UndoOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
o.Resources = args o.Resources = args
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetClientSideDryRun(cmd)
var err error var err error
if o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace(); err != nil { if o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace(); err != nil {

View File

@ -217,7 +217,7 @@ func (o *RunOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
} }
o.ArgsLenAtDash = cmd.ArgsLenAtDash() o.ArgsLenAtDash = cmd.ArgsLenAtDash()
o.DryRun = cmdutil.GetFlagBool(cmd, "dry-run") o.DryRun = cmdutil.GetClientSideDryRun(cmd)
attachFlag := cmd.Flags().Lookup("attach") attachFlag := cmd.Flags().Lookup("attach")
if !attachFlag.Changed && o.Interactive { if !attachFlag.Changed && o.Interactive {

View File

@ -216,7 +216,7 @@ func (o *EnvOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
o.updatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn o.updatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn
o.output = cmdutil.GetFlagString(cmd, "output") o.output = cmdutil.GetFlagString(cmd, "output")
o.dryRun = cmdutil.GetDryRunFlag(cmd) o.dryRun = cmdutil.GetClientSideDryRun(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

View File

@ -138,7 +138,7 @@ func (o *SetImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
} }
o.UpdatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn o.UpdatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetClientSideDryRun(cmd)
o.Output = cmdutil.GetFlagString(cmd, "output") o.Output = cmdutil.GetFlagString(cmd, "output")
o.ResolveImage = resolveImageFunc o.ResolveImage = resolveImageFunc

View File

@ -150,7 +150,7 @@ func (o *SetResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, ar
o.UpdatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn o.UpdatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn
o.Output = cmdutil.GetFlagString(cmd, "output") o.Output = cmdutil.GetFlagString(cmd, "output")
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetClientSideDryRun(cmd)
if o.DryRun { if o.DryRun {
o.PrintFlags.Complete("%s (dry run)") o.PrintFlags.Complete("%s (dry run)")

View File

@ -129,7 +129,7 @@ func (o *SetSelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg
return err return err
} }
o.dryrun = cmdutil.GetDryRunFlag(cmd) o.dryrun = cmdutil.GetClientSideDryRun(cmd)
o.resources, o.selector, err = getResourcesAndSelector(args) o.resources, o.selector, err = getResourcesAndSelector(args)
if err != nil { if err != nil {

View File

@ -128,7 +128,7 @@ 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.dryRun = cmdutil.GetDryRunFlag(cmd) o.dryRun = cmdutil.GetClientSideDryRun(cmd)
o.output = cmdutil.GetFlagString(cmd, "output") o.output = cmdutil.GetFlagString(cmd, "output")
o.updatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn o.updatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn

View File

@ -120,7 +120,7 @@ func NewCmdSubject(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobr
// Complete completes all required options // Complete completes all required options
func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
o.Output = cmdutil.GetFlagString(cmd, "output") o.Output = cmdutil.GetFlagString(cmd, "output")
o.DryRun = cmdutil.GetDryRunFlag(cmd) o.DryRun = cmdutil.GetClientSideDryRun(cmd)
if o.DryRun { if o.DryRun {
o.PrintFlags.Complete("%s (dry run)") o.PrintFlags.Complete("%s (dry run)")

View File

@ -23,6 +23,7 @@ import (
"io" "io"
"net/url" "net/url"
"os" "os"
"strconv"
"strings" "strings"
"time" "time"
@ -409,7 +410,12 @@ func AddKustomizeFlag(flags *pflag.FlagSet, value *string) {
// AddDryRunFlag adds dry-run flag to a command. Usually used by mutations. // AddDryRunFlag adds dry-run flag to a command. Usually used by mutations.
func AddDryRunFlag(cmd *cobra.Command) { func AddDryRunFlag(cmd *cobra.Command) {
cmd.Flags().Bool("dry-run", false, "If true, only print the object that would be sent, without sending it.") cmd.Flags().String(
"dry-run",
"none",
`Must be "none", "server", or "client". If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource.`,
)
cmd.Flags().Lookup("dry-run").NoOptDefVal = "unchanged"
} }
func AddServerSideApplyFlags(cmd *cobra.Command) { func AddServerSideApplyFlags(cmd *cobra.Command) {
@ -498,8 +504,69 @@ func GetFieldManagerFlag(cmd *cobra.Command) string {
return GetFlagString(cmd, "field-manager") return GetFlagString(cmd, "field-manager")
} }
func GetDryRunFlag(cmd *cobra.Command) bool { type DryRunStrategy int
return GetFlagBool(cmd, "dry-run")
const (
DryRunNone DryRunStrategy = iota
DryRunClient
DryRunServer
)
// TODO(julianvmodesto): remove GetClientSideDryRun once we support
// server-side dry-run in all commands
func GetClientSideDryRun(cmd *cobra.Command) bool {
dryRunStrategy, err := GetDryRunStrategy(cmd)
if err != nil {
klog.Fatalf("error accessing --dry-run flag for command %s: %v", cmd.Name(), err)
}
if dryRunStrategy == DryRunServer {
klog.Fatalf("--dry-run=server for command %s is not supported yet", cmd.Name())
}
return dryRunStrategy == DryRunClient
}
func GetDryRunStrategy(cmd *cobra.Command) (DryRunStrategy, error) {
var dryRunFlag = GetFlagString(cmd, "dry-run")
b, err := strconv.ParseBool(dryRunFlag)
// The flag is not a boolean
if err != nil {
switch dryRunFlag {
case cmd.Flag("dry-run").NoOptDefVal:
klog.Warning(`--dry-run is deprecated and can be replaced with --dry-run=client.`)
return DryRunClient, nil
case "client":
return DryRunClient, nil
case "server":
return DryRunServer, nil
case "none":
return DryRunNone, nil
default:
return DryRunNone, fmt.Errorf(`Invalid dry-run value (%v). Must be "none", "server", or "client".`, dryRunFlag)
}
}
// The flag was a boolean
if b {
klog.Warningf(`--dry-run=%v is deprecated (boolean value) and can be replaced with --dry-run=%s.`, dryRunFlag, "client")
return DryRunClient, nil
}
klog.Warningf(`--dry-run=%v is deprecated (boolean value) and can be replaced with --dry-run=%s.`, dryRunFlag, "none")
return DryRunNone, nil
}
// PrintFlagsWithDryRunStrategy sets a success message at print time for the dry run strategy
//
// TODO(juanvallejo): This can be cleaned up even further by creating
// a PrintFlags struct that binds the --dry-run flag, and whose
// ToPrinter method returns a printer that understands how to print
// this success message.
func PrintFlagsWithDryRunStrategy(printFlags *genericclioptions.PrintFlags, dryRunStrategy DryRunStrategy) *genericclioptions.PrintFlags {
switch dryRunStrategy {
case DryRunClient:
printFlags.Complete("%s (dry run)")
case DryRunServer:
printFlags.Complete("%s (server dry run)")
}
return printFlags
} }
// 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