update default run function for sub-commands

This patch updates parent commands of sub-commands to exit with a usage
error and exit code 1 on an invalid (non-sub-command) argument.
This commit is contained in:
juanvallejo 2016-10-20 10:41:46 -04:00
parent f67ecd73f7
commit 988e747649
11 changed files with 40 additions and 40 deletions

View File

@ -239,7 +239,7 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
{ {
Message: "Deploy Commands:", Message: "Deploy Commands:",
Commands: []*cobra.Command{ Commands: []*cobra.Command{
rollout.NewCmdRollout(f, out), rollout.NewCmdRollout(f, out, err),
NewCmdRollingUpdate(f, out), NewCmdRollingUpdate(f, out),
NewCmdScale(f, out), NewCmdScale(f, out),
NewCmdAutoscale(f, out), NewCmdAutoscale(f, out),
@ -249,7 +249,7 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
Message: "Cluster Management Commands:", Message: "Cluster Management Commands:",
Commands: []*cobra.Command{ Commands: []*cobra.Command{
NewCmdClusterInfo(f, out), NewCmdClusterInfo(f, out),
NewCmdTop(f, out), NewCmdTop(f, out, err),
NewCmdCordon(f, out), NewCmdCordon(f, out),
NewCmdUncordon(f, out), NewCmdUncordon(f, out),
NewCmdDrain(f, out), NewCmdDrain(f, out),
@ -304,7 +304,7 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
) )
} }
cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), out)) cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), out, err))
cmds.AddCommand(NewCmdVersion(f, out)) cmds.AddCommand(NewCmdVersion(f, out))
cmds.AddCommand(NewCmdApiVersions(f, out)) cmds.AddCommand(NewCmdApiVersions(f, out))
cmds.AddCommand(NewCmdOptions(out)) cmds.AddCommand(NewCmdOptions(out))

View File

@ -25,10 +25,11 @@ import (
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
) )
// NewCmdConfig creates a command object for the "config" action, and adds all child commands to it. // NewCmdConfig creates a command object for the "config" action, and adds all child commands to it.
func NewCmdConfig(pathOptions *clientcmd.PathOptions, out io.Writer) *cobra.Command { func NewCmdConfig(pathOptions *clientcmd.PathOptions, out, errOut io.Writer) *cobra.Command {
if len(pathOptions.ExplicitFileFlag) == 0 { if len(pathOptions.ExplicitFileFlag) == 0 {
pathOptions.ExplicitFileFlag = clientcmd.RecommendedConfigPathFlag pathOptions.ExplicitFileFlag = clientcmd.RecommendedConfigPathFlag
} }
@ -44,9 +45,7 @@ func NewCmdConfig(pathOptions *clientcmd.PathOptions, out io.Writer) *cobra.Comm
1. If the --` + pathOptions.ExplicitFileFlag + ` flag is set, then only that file is loaded. The flag may only be set once and no merging takes place. 1. If the --` + pathOptions.ExplicitFileFlag + ` flag is set, then only that file is loaded. The flag may only be set once and no merging takes place.
2. If $` + pathOptions.EnvVar + ` environment variable is set, then it is used a list of paths (normal path delimitting rules for your system). These paths are merged. When a value is modified, it is modified in the file that defines the stanza. When a value is created, it is created in the first file that exists. If no files in the chain exist, then it creates the last file in the list. 2. If $` + pathOptions.EnvVar + ` environment variable is set, then it is used a list of paths (normal path delimitting rules for your system). These paths are merged. When a value is modified, it is modified in the file that defines the stanza. When a value is created, it is created in the first file that exists. If no files in the chain exist, then it creates the last file in the list.
3. Otherwise, ` + path.Join("${HOME}", pathOptions.GlobalFileSubpath) + ` is used and no merging takes place.`), 3. Otherwise, ` + path.Join("${HOME}", pathOptions.GlobalFileSubpath) + ` is used and no merging takes place.`),
Run: func(cmd *cobra.Command, args []string) { Run: cmdutil.DefaultSubCommandRun(errOut),
cmd.Help()
},
} }
// file paths are common to all sub commands // file paths are common to all sub commands

View File

@ -770,7 +770,7 @@ func testConfigCommand(args []string, startingConfig clientcmdapi.Config, t *tes
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdConfig(clientcmd.NewDefaultPathOptions(), buf) cmd := NewCmdConfig(clientcmd.NewDefaultPathOptions(), buf, buf)
cmd.SetArgs(argsToUse) cmd.SetArgs(argsToUse)
cmd.Execute() cmd.Execute()

View File

@ -58,7 +58,8 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
Example: create_example, Example: create_example,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
if cmdutil.IsFilenameEmpty(options.Filenames) { if cmdutil.IsFilenameEmpty(options.Filenames) {
cmd.Help() defaultRunFunc := cmdutil.DefaultSubCommandRun(errOut)
defaultRunFunc(cmd, args)
return return
} }
cmdutil.CheckErr(ValidateArgs(cmd, args)) cmdutil.CheckErr(ValidateArgs(cmd, args))
@ -81,10 +82,10 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
// create subcommands // create subcommands
cmd.AddCommand(NewCmdCreateNamespace(f, out)) cmd.AddCommand(NewCmdCreateNamespace(f, out))
cmd.AddCommand(NewCmdCreateQuota(f, out)) cmd.AddCommand(NewCmdCreateQuota(f, out))
cmd.AddCommand(NewCmdCreateSecret(f, out)) cmd.AddCommand(NewCmdCreateSecret(f, out, errOut))
cmd.AddCommand(NewCmdCreateConfigMap(f, out)) cmd.AddCommand(NewCmdCreateConfigMap(f, out))
cmd.AddCommand(NewCmdCreateServiceAccount(f, out)) cmd.AddCommand(NewCmdCreateServiceAccount(f, out))
cmd.AddCommand(NewCmdCreateService(f, out)) cmd.AddCommand(NewCmdCreateService(f, out, errOut))
cmd.AddCommand(NewCmdCreateDeployment(f, out)) cmd.AddCommand(NewCmdCreateDeployment(f, out))
return cmd return cmd
} }

View File

@ -28,14 +28,12 @@ import (
) )
// NewCmdCreateSecret groups subcommands to create various types of secrets // NewCmdCreateSecret groups subcommands to create various types of secrets
func NewCmdCreateSecret(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { func NewCmdCreateSecret(f cmdutil.Factory, cmdOut, errOut io.Writer) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "secret", Use: "secret",
Short: "Create a secret using specified subcommand", Short: "Create a secret using specified subcommand",
Long: "Create a secret using specified subcommand.", Long: "Create a secret using specified subcommand.",
Run: func(cmd *cobra.Command, args []string) { Run: cmdutil.DefaultSubCommandRun(errOut),
cmd.Help()
},
} }
cmd.AddCommand(NewCmdCreateSecretDockerRegistry(f, cmdOut)) cmd.AddCommand(NewCmdCreateSecretDockerRegistry(f, cmdOut))
cmd.AddCommand(NewCmdCreateSecretTLS(f, cmdOut)) cmd.AddCommand(NewCmdCreateSecretTLS(f, cmdOut))

View File

@ -29,15 +29,13 @@ import (
) )
// NewCmdCreateService is a macro command to create a new service // NewCmdCreateService is a macro command to create a new service
func NewCmdCreateService(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { func NewCmdCreateService(f cmdutil.Factory, cmdOut, errOut io.Writer) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "service", Use: "service",
Aliases: []string{"svc"}, Aliases: []string{"svc"},
Short: "Create a service using specified subcommand.", Short: "Create a service using specified subcommand.",
Long: "Create a service using specified subcommand.", Long: "Create a service using specified subcommand.",
Run: func(cmd *cobra.Command, args []string) { Run: cmdutil.DefaultSubCommandRun(errOut),
cmd.Help()
},
} }
cmd.AddCommand(NewCmdCreateServiceClusterIP(f, cmdOut)) cmd.AddCommand(NewCmdCreateServiceClusterIP(f, cmdOut))
cmd.AddCommand(NewCmdCreateServiceNodePort(f, cmdOut)) cmd.AddCommand(NewCmdCreateServiceNodePort(f, cmdOut))

View File

@ -39,16 +39,14 @@ var (
`) `)
) )
func NewCmdRollout(f cmdutil.Factory, out io.Writer) *cobra.Command { func NewCmdRollout(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "rollout SUBCOMMAND", Use: "rollout SUBCOMMAND",
Short: "Manage a deployment rollout", Short: "Manage a deployment rollout",
Long: rollout_long, Long: rollout_long,
Example: rollout_example, Example: rollout_example,
Run: func(cmd *cobra.Command, args []string) { Run: cmdutil.DefaultSubCommandRun(errOut),
cmd.Help()
},
} }
// subcommands // subcommands
cmd.AddCommand(NewCmdRolloutHistory(f, out)) cmd.AddCommand(NewCmdRolloutHistory(f, out))

View File

@ -36,9 +36,7 @@ func NewCmdSet(f cmdutil.Factory, out, err io.Writer) *cobra.Command {
Use: "set SUBCOMMAND", Use: "set SUBCOMMAND",
Short: "Set specific features on objects", Short: "Set specific features on objects",
Long: set_long, Long: set_long,
Run: func(cmd *cobra.Command, args []string) { Run: cmdutil.DefaultSubCommandRun(err),
cmd.Help()
},
} }
// add subcommands // add subcommands

View File

@ -35,18 +35,12 @@ var (
The top command allows you to see the resource consumption for nodes or pods.`) The top command allows you to see the resource consumption for nodes or pods.`)
) )
func NewCmdTop(f cmdutil.Factory, out io.Writer) *cobra.Command { func NewCmdTop(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command {
options := &TopOptions{}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "top", Use: "top",
Short: "Display Resource (CPU/Memory/Storage) usage", Short: "Display Resource (CPU/Memory/Storage) usage",
Long: topLong, Long: topLong,
Run: func(cmd *cobra.Command, args []string) { Run: cmdutil.DefaultSubCommandRun(errOut),
if err := options.RunTop(f, cmd, args, out); err != nil {
cmdutil.CheckErr(err)
}
},
} }
// create subcommands // create subcommands
@ -54,7 +48,3 @@ func NewCmdTop(f cmdutil.Factory, out io.Writer) *cobra.Command {
cmd.AddCommand(NewCmdTopPod(f, out)) cmd.AddCommand(NewCmdTopPod(f, out))
return cmd return cmd
} }
func (o TopOptions) RunTop(f cmdutil.Factory, cmd *cobra.Command, args []string, out io.Writer) error {
return cmd.Help()
}

View File

@ -23,13 +23,14 @@ import (
"io/ioutil" "io/ioutil"
"time" "time"
"testing"
metrics_api "k8s.io/heapster/metrics/apis/metrics/v1alpha1" metrics_api "k8s.io/heapster/metrics/apis/metrics/v1alpha1"
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
"k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/resource"
"k8s.io/kubernetes/pkg/api/unversioned" "k8s.io/kubernetes/pkg/api/unversioned"
v1 "k8s.io/kubernetes/pkg/api/v1" v1 "k8s.io/kubernetes/pkg/api/v1"
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
"testing"
) )
const ( const (
@ -44,7 +45,7 @@ func TestTopSubcommandsExist(t *testing.T) {
f, _, _, _ := cmdtesting.NewAPIFactory() f, _, _, _ := cmdtesting.NewAPIFactory()
buf := bytes.NewBuffer([]byte{}) buf := bytes.NewBuffer([]byte{})
cmd := NewCmdTop(f, buf) cmd := NewCmdTop(f, buf, buf)
if !cmd.HasSubCommands() { if !cmd.HasSubCommands() {
t.Error("top command should have subcommands") t.Error("top command should have subcommands")
} }

View File

@ -752,3 +752,20 @@ func IsSiblingCommandExists(cmd *cobra.Command, targetCmdName string) bool {
return false return false
} }
// DefaultSubCommandRun prints a command's help string to the specified output if no
// arguments (sub-commands) are provided, or a usage error otherwise.
func DefaultSubCommandRun(out io.Writer) func(c *cobra.Command, args []string) {
return func(c *cobra.Command, args []string) {
c.SetOutput(out)
RequireNoArguments(c, args)
c.Help()
}
}
// RequireNoArguments exits with a usage error if extra arguments are provided.
func RequireNoArguments(c *cobra.Command, args []string) {
if len(args) > 0 {
CheckErr(UsageError(c, fmt.Sprintf(`unknown command %q`, strings.Join(args, " "))))
}
}