diff --git a/pkg/kubectl/cmd/cmd.go b/pkg/kubectl/cmd/cmd.go index d06839698a8..198fa5c81a9 100644 --- a/pkg/kubectl/cmd/cmd.go +++ b/pkg/kubectl/cmd/cmd.go @@ -287,7 +287,7 @@ Find more information at https://github.com/kubernetes/kubernetes.`, NewCmdDescribe(f, out, err), NewCmdLogs(f, out), NewCmdAttach(f, in, out, err), - NewCmdExec("kubectl", f, in, out, err), + NewCmdExec(f, in, out, err), NewCmdPortForward(f, out, err), NewCmdProxy(f, out), }, diff --git a/pkg/kubectl/cmd/exec.go b/pkg/kubectl/cmd/exec.go index 62c1f92f814..b16c6931da4 100644 --- a/pkg/kubectl/cmd/exec.go +++ b/pkg/kubectl/cmd/exec.go @@ -52,7 +52,7 @@ const ( execUsageStr = "expected 'exec POD_NAME COMMAND [ARG1] [ARG2] ... [ARGN]'.\nPOD_NAME and COMMAND are required arguments for the exec command" ) -func NewCmdExec(cmdFullName string, f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command { +func NewCmdExec(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command { options := &ExecOptions{ StreamOptions: StreamOptions{ In: cmdIn, @@ -60,8 +60,7 @@ func NewCmdExec(cmdFullName string, f *cmdutil.Factory, cmdIn io.Reader, cmdOut, Err: cmdErr, }, - FullCmdName: cmdFullName, - Executor: &DefaultRemoteExecutor{}, + Executor: &DefaultRemoteExecutor{}, } cmd := &cobra.Command{ Use: "exec POD [-c CONTAINER] -- COMMAND [args...]", @@ -131,18 +130,16 @@ type ExecOptions struct { Command []string - FullCmdName string - Executor RemoteExecutor - PodClient coreclient.PodsGetter - Config *restclient.Config + FullCmdName string + SuggestedCmdUsage string + + Executor RemoteExecutor + PodClient coreclient.PodsGetter + Config *restclient.Config } // Complete verifies command line arguments and loads data from the command environment func (p *ExecOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, argsIn []string, argsLenAtDash int) error { - if len(p.FullCmdName) == 0 { - p.FullCmdName = "kubectl" - } - // Let kubectl exec follow rules for `--`, see #13004 issue if len(p.PodName) == 0 && (len(argsIn) == 0 || argsLenAtDash == 0) { return cmdutil.UsageError(cmd, execUsageStr) @@ -161,6 +158,14 @@ func (p *ExecOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, argsIn [] } } + cmdParent := cmd.Parent() + if cmdParent != nil { + p.FullCmdName = cmdParent.CommandPath() + } + if len(p.FullCmdName) > 0 && cmdutil.IsSiblingCommandExists(cmd, "describe") { + p.SuggestedCmdUsage = fmt.Sprintf("Use '%s describe pod/%s' to see all of the containers in this pod.", p.FullCmdName, p.PodName) + } + namespace, _, err := f.DefaultNamespace() if err != nil { return err @@ -265,7 +270,11 @@ func (p *ExecOptions) Run() error { containerName := p.ContainerName if len(containerName) == 0 { if len(pod.Spec.Containers) > 1 { - fmt.Fprintf(p.Err, "defaulting container name to %s, use '%s describe pod/%s' to see all container names\n", pod.Spec.Containers[0].Name, p.FullCmdName, p.PodName) + usageString := fmt.Sprintf("Defaulting container name to %s.", pod.Spec.Containers[0].Name) + if len(p.SuggestedCmdUsage) > 0 { + usageString = fmt.Sprintf("%s\n%s", usageString, p.SuggestedCmdUsage) + } + fmt.Fprintf(p.Err, "%s\n", usageString) } containerName = pod.Spec.Containers[0].Name } diff --git a/pkg/kubectl/cmd/get.go b/pkg/kubectl/cmd/get.go index 4a4ea3d5e7e..9a53f41ee7d 100644 --- a/pkg/kubectl/cmd/get.go +++ b/pkg/kubectl/cmd/get.go @@ -171,7 +171,14 @@ func RunGet(f *cmdutil.Factory, out io.Writer, errOut io.Writer, cmd *cobra.Comm if len(args) == 0 && cmdutil.IsFilenameEmpty(options.Filenames) { fmt.Fprint(errOut, "You must specify the type of resource to get. ", valid_resources) - return cmdutil.UsageError(cmd, "Required resource not specified.") + + fullCmdName := cmd.Parent().CommandPath() + usageString := "Required resource not specified." + if len(fullCmdName) > 0 && cmdutil.IsSiblingCommandExists(cmd, "explain") { + usageString = fmt.Sprintf("%s\nUse \"%s explain \" for a detailed description of that resource (e.g. %[2]s explain pods).", usageString, fullCmdName) + } + + return cmdutil.UsageError(cmd, usageString) } // determine if args contains "all" diff --git a/pkg/kubectl/cmd/util/helpers.go b/pkg/kubectl/cmd/util/helpers.go index 837aafbe910..97f6ce0d369 100644 --- a/pkg/kubectl/cmd/util/helpers.go +++ b/pkg/kubectl/cmd/util/helpers.go @@ -716,3 +716,15 @@ func ObjectListToVersionedObject(objects []runtime.Object, version unversioned.G } return converted, nil } + +// IsSiblingCommandExists receives a pointer to a cobra command and a target string. +// Returns true if the target string is found in the list of sibling commands. +func IsSiblingCommandExists(cmd *cobra.Command, targetCmdName string) bool { + for _, c := range cmd.Parent().Commands() { + if c.Name() == targetCmdName { + return true + } + } + + return false +}