diff --git a/pkg/kubectl/cmd/cmd.go b/pkg/kubectl/cmd/cmd.go index abdb1244768..392023f3c82 100644 --- a/pkg/kubectl/cmd/cmd.go +++ b/pkg/kubectl/cmd/cmd.go @@ -239,7 +239,7 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob { Message: "Deploy Commands:", Commands: []*cobra.Command{ - rollout.NewCmdRollout(f, out), + rollout.NewCmdRollout(f, out, err), NewCmdRollingUpdate(f, out), NewCmdScale(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:", Commands: []*cobra.Command{ NewCmdClusterInfo(f, out), - NewCmdTop(f, out), + NewCmdTop(f, out, err), NewCmdCordon(f, out), NewCmdUncordon(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(NewCmdApiVersions(f, out)) cmds.AddCommand(NewCmdOptions(out)) diff --git a/pkg/kubectl/cmd/config/config.go b/pkg/kubectl/cmd/config/config.go index 76860a3d37c..2b445f16fb4 100644 --- a/pkg/kubectl/cmd/config/config.go +++ b/pkg/kubectl/cmd/config/config.go @@ -25,10 +25,11 @@ import ( "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" "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. -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 { 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. 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.`), - Run: func(cmd *cobra.Command, args []string) { - cmd.Help() - }, + Run: cmdutil.DefaultSubCommandRun(errOut), } // file paths are common to all sub commands diff --git a/pkg/kubectl/cmd/config/config_test.go b/pkg/kubectl/cmd/config/config_test.go index aef650dea10..e52f85e8834 100644 --- a/pkg/kubectl/cmd/config/config_test.go +++ b/pkg/kubectl/cmd/config/config_test.go @@ -770,7 +770,7 @@ func testConfigCommand(args []string, startingConfig clientcmdapi.Config, t *tes buf := bytes.NewBuffer([]byte{}) - cmd := NewCmdConfig(clientcmd.NewDefaultPathOptions(), buf) + cmd := NewCmdConfig(clientcmd.NewDefaultPathOptions(), buf, buf) cmd.SetArgs(argsToUse) cmd.Execute() diff --git a/pkg/kubectl/cmd/create.go b/pkg/kubectl/cmd/create.go index a8d0bc8e838..bc8f34ef6c1 100644 --- a/pkg/kubectl/cmd/create.go +++ b/pkg/kubectl/cmd/create.go @@ -58,7 +58,8 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { Example: create_example, Run: func(cmd *cobra.Command, args []string) { if cmdutil.IsFilenameEmpty(options.Filenames) { - cmd.Help() + defaultRunFunc := cmdutil.DefaultSubCommandRun(errOut) + defaultRunFunc(cmd, args) return } cmdutil.CheckErr(ValidateArgs(cmd, args)) @@ -81,10 +82,10 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { // create subcommands cmd.AddCommand(NewCmdCreateNamespace(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(NewCmdCreateServiceAccount(f, out)) - cmd.AddCommand(NewCmdCreateService(f, out)) + cmd.AddCommand(NewCmdCreateService(f, out, errOut)) cmd.AddCommand(NewCmdCreateDeployment(f, out)) return cmd } diff --git a/pkg/kubectl/cmd/create_secret.go b/pkg/kubectl/cmd/create_secret.go index 8495f4db79b..e2475bb100f 100644 --- a/pkg/kubectl/cmd/create_secret.go +++ b/pkg/kubectl/cmd/create_secret.go @@ -28,14 +28,12 @@ import ( ) // 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{ Use: "secret", Short: "Create a secret using specified subcommand", Long: "Create a secret using specified subcommand.", - Run: func(cmd *cobra.Command, args []string) { - cmd.Help() - }, + Run: cmdutil.DefaultSubCommandRun(errOut), } cmd.AddCommand(NewCmdCreateSecretDockerRegistry(f, cmdOut)) cmd.AddCommand(NewCmdCreateSecretTLS(f, cmdOut)) diff --git a/pkg/kubectl/cmd/create_service.go b/pkg/kubectl/cmd/create_service.go index 06655687800..71eaed66296 100644 --- a/pkg/kubectl/cmd/create_service.go +++ b/pkg/kubectl/cmd/create_service.go @@ -29,15 +29,13 @@ import ( ) // 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{ Use: "service", Aliases: []string{"svc"}, Short: "Create a service using specified subcommand.", Long: "Create a service using specified subcommand.", - Run: func(cmd *cobra.Command, args []string) { - cmd.Help() - }, + Run: cmdutil.DefaultSubCommandRun(errOut), } cmd.AddCommand(NewCmdCreateServiceClusterIP(f, cmdOut)) cmd.AddCommand(NewCmdCreateServiceNodePort(f, cmdOut)) diff --git a/pkg/kubectl/cmd/rollout/rollout.go b/pkg/kubectl/cmd/rollout/rollout.go index 1f9a6870e8d..a9b9ad8776a 100644 --- a/pkg/kubectl/cmd/rollout/rollout.go +++ b/pkg/kubectl/cmd/rollout/rollout.go @@ -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{ Use: "rollout SUBCOMMAND", Short: "Manage a deployment rollout", Long: rollout_long, Example: rollout_example, - Run: func(cmd *cobra.Command, args []string) { - cmd.Help() - }, + Run: cmdutil.DefaultSubCommandRun(errOut), } // subcommands cmd.AddCommand(NewCmdRolloutHistory(f, out)) diff --git a/pkg/kubectl/cmd/set/set.go b/pkg/kubectl/cmd/set/set.go index 01a0b29a480..64bcb6fa139 100644 --- a/pkg/kubectl/cmd/set/set.go +++ b/pkg/kubectl/cmd/set/set.go @@ -36,9 +36,7 @@ func NewCmdSet(f cmdutil.Factory, out, err io.Writer) *cobra.Command { Use: "set SUBCOMMAND", Short: "Set specific features on objects", Long: set_long, - Run: func(cmd *cobra.Command, args []string) { - cmd.Help() - }, + Run: cmdutil.DefaultSubCommandRun(err), } // add subcommands diff --git a/pkg/kubectl/cmd/top.go b/pkg/kubectl/cmd/top.go index af4f27cc3b1..bb4080bf2ac 100644 --- a/pkg/kubectl/cmd/top.go +++ b/pkg/kubectl/cmd/top.go @@ -35,18 +35,12 @@ var ( The top command allows you to see the resource consumption for nodes or pods.`) ) -func NewCmdTop(f cmdutil.Factory, out io.Writer) *cobra.Command { - options := &TopOptions{} - +func NewCmdTop(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { cmd := &cobra.Command{ Use: "top", Short: "Display Resource (CPU/Memory/Storage) usage", Long: topLong, - Run: func(cmd *cobra.Command, args []string) { - if err := options.RunTop(f, cmd, args, out); err != nil { - cmdutil.CheckErr(err) - } - }, + Run: cmdutil.DefaultSubCommandRun(errOut), } // create subcommands @@ -54,7 +48,3 @@ func NewCmdTop(f cmdutil.Factory, out io.Writer) *cobra.Command { cmd.AddCommand(NewCmdTopPod(f, out)) return cmd } - -func (o TopOptions) RunTop(f cmdutil.Factory, cmd *cobra.Command, args []string, out io.Writer) error { - return cmd.Help() -} diff --git a/pkg/kubectl/cmd/top_test.go b/pkg/kubectl/cmd/top_test.go index c5bf0dfab6d..80dff6c5af6 100644 --- a/pkg/kubectl/cmd/top_test.go +++ b/pkg/kubectl/cmd/top_test.go @@ -23,13 +23,14 @@ import ( "io/ioutil" "time" + "testing" + metrics_api "k8s.io/heapster/metrics/apis/metrics/v1alpha1" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/unversioned" v1 "k8s.io/kubernetes/pkg/api/v1" cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing" - "testing" ) const ( @@ -44,7 +45,7 @@ func TestTopSubcommandsExist(t *testing.T) { f, _, _, _ := cmdtesting.NewAPIFactory() buf := bytes.NewBuffer([]byte{}) - cmd := NewCmdTop(f, buf) + cmd := NewCmdTop(f, buf, buf) if !cmd.HasSubCommands() { t.Error("top command should have subcommands") } diff --git a/pkg/kubectl/cmd/util/helpers.go b/pkg/kubectl/cmd/util/helpers.go index 5c8e972bd6b..be7c4ea8b98 100644 --- a/pkg/kubectl/cmd/util/helpers.go +++ b/pkg/kubectl/cmd/util/helpers.go @@ -752,3 +752,20 @@ func IsSiblingCommandExists(cmd *cobra.Command, targetCmdName string) bool { 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, " ")))) + } +}