2019-01-12 04:58:27 +00:00
/ *
Copyright 2014 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package cmd
import (
"flag"
"fmt"
"io"
"os"
"os/exec"
2019-09-27 21:51:53 +00:00
"runtime"
2019-01-12 04:58:27 +00:00
"strings"
"syscall"
"github.com/spf13/cobra"
2020-08-10 17:43:49 +00:00
"k8s.io/client-go/rest"
2019-01-12 04:58:27 +00:00
"k8s.io/client-go/tools/clientcmd"
2019-04-07 17:07:55 +00:00
cliflag "k8s.io/component-base/cli/flag"
2019-09-27 21:51:53 +00:00
"k8s.io/kubectl/pkg/cmd/annotate"
"k8s.io/kubectl/pkg/cmd/apiresources"
"k8s.io/kubectl/pkg/cmd/apply"
"k8s.io/kubectl/pkg/cmd/attach"
2020-12-01 01:06:26 +00:00
"k8s.io/kubectl/pkg/cmd/auth"
2019-09-27 21:51:53 +00:00
"k8s.io/kubectl/pkg/cmd/autoscale"
"k8s.io/kubectl/pkg/cmd/certificates"
"k8s.io/kubectl/pkg/cmd/clusterinfo"
"k8s.io/kubectl/pkg/cmd/completion"
cmdconfig "k8s.io/kubectl/pkg/cmd/config"
2020-08-10 17:43:49 +00:00
"k8s.io/kubectl/pkg/cmd/cp"
2019-09-27 21:51:53 +00:00
"k8s.io/kubectl/pkg/cmd/create"
2020-12-01 01:06:26 +00:00
"k8s.io/kubectl/pkg/cmd/debug"
2019-09-27 21:51:53 +00:00
"k8s.io/kubectl/pkg/cmd/delete"
"k8s.io/kubectl/pkg/cmd/describe"
"k8s.io/kubectl/pkg/cmd/diff"
"k8s.io/kubectl/pkg/cmd/drain"
"k8s.io/kubectl/pkg/cmd/edit"
cmdexec "k8s.io/kubectl/pkg/cmd/exec"
"k8s.io/kubectl/pkg/cmd/explain"
"k8s.io/kubectl/pkg/cmd/expose"
2019-12-12 01:27:03 +00:00
"k8s.io/kubectl/pkg/cmd/get"
2019-09-27 21:51:53 +00:00
"k8s.io/kubectl/pkg/cmd/label"
"k8s.io/kubectl/pkg/cmd/logs"
"k8s.io/kubectl/pkg/cmd/options"
"k8s.io/kubectl/pkg/cmd/patch"
"k8s.io/kubectl/pkg/cmd/plugin"
"k8s.io/kubectl/pkg/cmd/portforward"
"k8s.io/kubectl/pkg/cmd/proxy"
"k8s.io/kubectl/pkg/cmd/replace"
"k8s.io/kubectl/pkg/cmd/rollout"
"k8s.io/kubectl/pkg/cmd/run"
"k8s.io/kubectl/pkg/cmd/scale"
"k8s.io/kubectl/pkg/cmd/set"
"k8s.io/kubectl/pkg/cmd/taint"
"k8s.io/kubectl/pkg/cmd/top"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/cmd/version"
"k8s.io/kubectl/pkg/cmd/wait"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
2020-08-10 17:43:49 +00:00
"k8s.io/kubectl/pkg/util/term"
2019-01-12 04:58:27 +00:00
"k8s.io/cli-runtime/pkg/genericclioptions"
2019-09-27 21:51:53 +00:00
"k8s.io/kubectl/pkg/cmd/kustomize"
2019-01-12 04:58:27 +00:00
)
const (
bashCompletionFunc = ` # call kubectl get $ 1 ,
2019-09-27 21:51:53 +00:00
__kubectl_debug_out ( )
{
local cmd = "$1"
__kubectl_debug "${FUNCNAME[1]}: get completion by ${cmd}"
eval "${cmd} 2>/dev/null"
}
2019-01-12 04:58:27 +00:00
__kubectl_override_flag_list = ( -- kubeconfig -- cluster -- user -- context -- namespace -- server - n - s )
__kubectl_override_flags ( )
{
local $ { __kubectl_override_flag_list [ * ] # # * - } two_word_of of var
for w in "${words[@]}" ; do
if [ - n "${two_word_of}" ] ; then
eval "${two_word_of##*-}=\"${two_word_of}=\${w}\""
two_word_of =
continue
fi
for of in "${__kubectl_override_flag_list[@]}" ; do
case "${w}" in
$ { of } = * )
eval "${of##*-}=\"${w}\""
; ;
$ { of } )
two_word_of = "${of}"
; ;
esac
done
done
for var in "${__kubectl_override_flag_list[@]##*-}" ; do
if eval "test -n \"\$${var}\"" ; then
2019-09-27 21:51:53 +00:00
eval "echo -n \${${var}}' '"
2019-01-12 04:58:27 +00:00
fi
done
}
__kubectl_config_get_contexts ( )
{
__kubectl_parse_config "contexts"
}
__kubectl_config_get_clusters ( )
{
__kubectl_parse_config "clusters"
}
__kubectl_config_get_users ( )
{
__kubectl_parse_config "users"
}
# $ 1 has to be "contexts" , "clusters" or "users"
__kubectl_parse_config ( )
{
local template kubectl_out
template = "{{ range .$1 }}{{ .name }} {{ end }}"
2019-09-27 21:51:53 +00:00
if kubectl_out = $ ( __kubectl_debug_out "kubectl config $(__kubectl_override_flags) -o template --template=\"${template}\" view" ) ; then
2019-01-12 04:58:27 +00:00
COMPREPLY = ( $ ( compgen - W "${kubectl_out[*]}" -- "$cur" ) )
fi
}
# $ 1 is the name of resource ( required )
# $ 2 is template string for kubectl get ( optional )
__kubectl_parse_get ( )
{
local template
template = "${2:-" { { range . items } } { { . metadata . name } } { { end } } "}"
local kubectl_out
2019-09-27 21:51:53 +00:00
if kubectl_out = $ ( __kubectl_debug_out "kubectl get $(__kubectl_override_flags) -o template --template=\"${template}\" \"$1\"" ) ; then
2019-01-12 04:58:27 +00:00
COMPREPLY += ( $ ( compgen - W "${kubectl_out[*]}" -- "$cur" ) )
fi
}
__kubectl_get_resource ( )
{
if [ [ $ { # nouns [ @ ] } - eq 0 ] ] ; then
local kubectl_out
2019-09-27 21:51:53 +00:00
if kubectl_out = $ ( __kubectl_debug_out "kubectl api-resources $(__kubectl_override_flags) -o name --cached --request-timeout=5s --verbs=get" ) ; then
2019-01-12 04:58:27 +00:00
COMPREPLY = ( $ ( compgen - W "${kubectl_out[*]}" -- "$cur" ) )
return 0
fi
return 1
fi
__kubectl_parse_get "${nouns[${#nouns[@]} -1]}"
}
__kubectl_get_resource_namespace ( )
{
__kubectl_parse_get "namespace"
}
__kubectl_get_resource_pod ( )
{
__kubectl_parse_get "pod"
}
__kubectl_get_resource_rc ( )
{
__kubectl_parse_get "rc"
}
__kubectl_get_resource_node ( )
{
__kubectl_parse_get "node"
}
__kubectl_get_resource_clusterrole ( )
{
__kubectl_parse_get "clusterrole"
}
# $ 1 is the name of the pod we want to get the list of containers inside
__kubectl_get_containers ( )
{
local template
template = "{{ range .spec.initContainers }}{{ .name }} {{end}}{{ range .spec.containers }}{{ .name }} {{ end }}"
__kubectl_debug "${FUNCNAME} nouns are ${nouns[*]}"
local len = "${#nouns[@]}"
if [ [ $ { len } - ne 1 ] ] ; then
return
fi
local last = $ { nouns [ $ { len } - 1 ] }
local kubectl_out
2019-09-27 21:51:53 +00:00
if kubectl_out = $ ( __kubectl_debug_out "kubectl get $(__kubectl_override_flags) -o template --template=\"${template}\" pods \"${last}\"" ) ; then
2019-01-12 04:58:27 +00:00
COMPREPLY = ( $ ( compgen - W "${kubectl_out[*]}" -- "$cur" ) )
fi
}
# Require both a pod and a container to be specified
__kubectl_require_pod_and_container ( )
{
if [ [ $ { # nouns [ @ ] } - eq 0 ] ] ; then
__kubectl_parse_get pods
return 0
fi ;
__kubectl_get_containers
return 0
}
__kubectl_cp ( )
{
if [ [ $ ( type - t compopt ) = "builtin" ] ] ; then
compopt - o nospace
fi
case "$cur" in
/ * | [ . ~ ] * ) # looks like a path
return
; ;
* : * ) # TODO : complete remote files in the pod
return
; ;
* / * ) # complete < namespace > / < pod >
local template namespace kubectl_out
template = "{{ range .items }}{{ .metadata.namespace }}/{{ .metadata.name }}: {{ end }}"
namespace = "${cur%%/*}"
2019-09-27 21:51:53 +00:00
if kubectl_out = $ ( __kubectl_debug_out "kubectl get $(__kubectl_override_flags) --namespace \"${namespace}\" -o template --template=\"${template}\" pods" ) ; then
2019-01-12 04:58:27 +00:00
COMPREPLY = ( $ ( compgen - W "${kubectl_out[*]}" -- "${cur}" ) )
fi
return
; ;
* ) # complete namespaces , pods , and filedirs
__kubectl_parse_get "namespace" "{{ range .items }}{{ .metadata.name }}/ {{ end }}"
__kubectl_parse_get "pod" "{{ range .items }}{{ .metadata.name }}: {{ end }}"
_filedir
; ;
esac
}
2019-09-27 21:51:53 +00:00
__kubectl_custom_func ( ) {
2019-01-12 04:58:27 +00:00
case $ { last_command } in
kubectl_get | kubectl_describe | kubectl_delete | kubectl_label | kubectl_edit | kubectl_patch | \
kubectl_annotate | kubectl_expose | kubectl_scale | kubectl_autoscale | kubectl_taint | kubectl_rollout_ * | \
kubectl_apply_edit - last - applied | kubectl_apply_view - last - applied )
__kubectl_get_resource
return
; ;
2019-04-07 17:07:55 +00:00
kubectl_logs )
2019-01-12 04:58:27 +00:00
__kubectl_require_pod_and_container
return
; ;
2019-04-07 17:07:55 +00:00
kubectl_exec | kubectl_port - forward | kubectl_top_pod | kubectl_attach )
2019-01-12 04:58:27 +00:00
__kubectl_get_resource_pod
return
; ;
kubectl_cordon | kubectl_uncordon | kubectl_drain | kubectl_top_node )
__kubectl_get_resource_node
return
; ;
2020-12-01 01:06:26 +00:00
kubectl_config_use - context | kubectl_config_rename - context | kubectl_config_delete - context )
2019-01-12 04:58:27 +00:00
__kubectl_config_get_contexts
return
; ;
kubectl_config_delete - cluster )
__kubectl_config_get_clusters
return
; ;
kubectl_cp )
__kubectl_cp
return
; ;
* )
; ;
esac
}
`
)
var (
bashCompletionFlags = map [ string ] string {
"namespace" : "__kubectl_get_resource_namespace" ,
"context" : "__kubectl_config_get_contexts" ,
"cluster" : "__kubectl_config_get_clusters" ,
"user" : "__kubectl_config_get_users" ,
}
)
// NewDefaultKubectlCommand creates the `kubectl` command with default arguments
func NewDefaultKubectlCommand ( ) * cobra . Command {
2019-04-07 17:07:55 +00:00
return NewDefaultKubectlCommandWithArgs ( NewDefaultPluginHandler ( plugin . ValidPluginFilenamePrefixes ) , os . Args , os . Stdin , os . Stdout , os . Stderr )
2019-01-12 04:58:27 +00:00
}
// NewDefaultKubectlCommandWithArgs creates the `kubectl` command with arguments
func NewDefaultKubectlCommandWithArgs ( pluginHandler PluginHandler , args [ ] string , in io . Reader , out , errout io . Writer ) * cobra . Command {
cmd := NewKubectlCommand ( in , out , errout )
if pluginHandler == nil {
return cmd
}
if len ( args ) > 1 {
cmdPathPieces := args [ 1 : ]
// only look for suitable extension executables if
// the specified command does not already exist
if _ , _ , err := cmd . Find ( cmdPathPieces ) ; err != nil {
2019-04-07 17:07:55 +00:00
if err := HandlePluginCommand ( pluginHandler , cmdPathPieces ) ; err != nil {
2020-12-01 01:06:26 +00:00
fmt . Fprintf ( errout , "Error: %v\n" , err )
2019-01-12 04:58:27 +00:00
os . Exit ( 1 )
}
}
}
return cmd
}
// PluginHandler is capable of parsing command line arguments
// and performing executable filename lookups to search
// for valid plugin files, and execute found plugins.
type PluginHandler interface {
2019-04-07 17:07:55 +00:00
// exists at the given filename, or a boolean false.
// Lookup will iterate over a list of given prefixes
// in order to recognize valid plugin filenames.
// The first filepath to match a prefix is returned.
Lookup ( filename string ) ( string , bool )
2019-01-12 04:58:27 +00:00
// Execute receives an executable's filepath, a slice
// of arguments, and a slice of environment variables
// to relay to the executable.
Execute ( executablePath string , cmdArgs , environment [ ] string ) error
}
2019-04-07 17:07:55 +00:00
// DefaultPluginHandler implements PluginHandler
type DefaultPluginHandler struct {
ValidPrefixes [ ] string
}
// NewDefaultPluginHandler instantiates the DefaultPluginHandler with a list of
// given filename prefixes used to identify valid plugin filenames.
func NewDefaultPluginHandler ( validPrefixes [ ] string ) * DefaultPluginHandler {
return & DefaultPluginHandler {
ValidPrefixes : validPrefixes ,
}
}
2019-01-12 04:58:27 +00:00
// Lookup implements PluginHandler
2019-04-07 17:07:55 +00:00
func ( h * DefaultPluginHandler ) Lookup ( filename string ) ( string , bool ) {
for _ , prefix := range h . ValidPrefixes {
path , err := exec . LookPath ( fmt . Sprintf ( "%s-%s" , prefix , filename ) )
if err != nil || len ( path ) == 0 {
continue
}
return path , true
2019-01-12 04:58:27 +00:00
}
2019-04-07 17:07:55 +00:00
return "" , false
2019-01-12 04:58:27 +00:00
}
// Execute implements PluginHandler
2019-04-07 17:07:55 +00:00
func ( h * DefaultPluginHandler ) Execute ( executablePath string , cmdArgs , environment [ ] string ) error {
2019-09-27 21:51:53 +00:00
// Windows does not support exec syscall.
if runtime . GOOS == "windows" {
cmd := exec . Command ( executablePath , cmdArgs ... )
cmd . Stdout = os . Stdout
cmd . Stderr = os . Stderr
cmd . Stdin = os . Stdin
cmd . Env = environment
err := cmd . Run ( )
if err == nil {
os . Exit ( 0 )
}
return err
}
// invoke cmd binary relaying the environment and args given
// append executablePath to cmdArgs, as execve will make first argument the "binary name".
return syscall . Exec ( executablePath , append ( [ ] string { executablePath } , cmdArgs ... ) , environment )
2019-01-12 04:58:27 +00:00
}
2019-04-07 17:07:55 +00:00
// HandlePluginCommand receives a pluginHandler and command-line arguments and attempts to find
// a plugin executable on the PATH that satisfies the given arguments.
func HandlePluginCommand ( pluginHandler PluginHandler , cmdArgs [ ] string ) error {
2020-12-01 01:06:26 +00:00
var remainingArgs [ ] string // all "non-flag" arguments
for _ , arg := range cmdArgs {
if strings . HasPrefix ( arg , "-" ) {
2019-01-12 04:58:27 +00:00
break
}
2020-12-01 01:06:26 +00:00
remainingArgs = append ( remainingArgs , strings . Replace ( arg , "-" , "_" , - 1 ) )
}
if len ( remainingArgs ) == 0 {
// the length of cmdArgs is at least 1
return fmt . Errorf ( "flags cannot be placed before plugin name: %s" , cmdArgs [ 0 ] )
2019-01-12 04:58:27 +00:00
}
foundBinaryPath := ""
// attempt to find binary, starting at longest possible name with given cmdArgs
for len ( remainingArgs ) > 0 {
2019-04-07 17:07:55 +00:00
path , found := pluginHandler . Lookup ( strings . Join ( remainingArgs , "-" ) )
if ! found {
2019-01-12 04:58:27 +00:00
remainingArgs = remainingArgs [ : len ( remainingArgs ) - 1 ]
continue
}
foundBinaryPath = path
break
}
if len ( foundBinaryPath ) == 0 {
return nil
}
// invoke cmd binary relaying the current environment and args given
2019-09-27 21:51:53 +00:00
if err := pluginHandler . Execute ( foundBinaryPath , cmdArgs [ len ( remainingArgs ) : ] , os . Environ ( ) ) ; err != nil {
2019-01-12 04:58:27 +00:00
return err
}
return nil
}
// NewKubectlCommand creates the `kubectl` command and its nested children.
func NewKubectlCommand ( in io . Reader , out , err io . Writer ) * cobra . Command {
2020-08-10 17:43:49 +00:00
warningHandler := rest . NewWarningWriter ( err , rest . WarningWriterOptions { Deduplicate : true , Color : term . AllowsColorOutput ( err ) } )
warningsAsErrors := false
2019-01-12 04:58:27 +00:00
// Parent command to which all subcommands are added.
cmds := & cobra . Command {
Use : "kubectl" ,
Short : i18n . T ( "kubectl controls the Kubernetes cluster manager" ) ,
Long : templates . LongDesc ( `
kubectl controls the Kubernetes cluster manager .
Find more information at :
https : //kubernetes.io/docs/reference/kubectl/overview/`),
Run : runHelp ,
// Hook before and after Run initialize and write profiles to disk,
// respectively.
PersistentPreRunE : func ( * cobra . Command , [ ] string ) error {
2020-08-10 17:43:49 +00:00
rest . SetDefaultWarningHandler ( warningHandler )
2019-01-12 04:58:27 +00:00
return initProfiling ( )
} ,
PersistentPostRunE : func ( * cobra . Command , [ ] string ) error {
2020-08-10 17:43:49 +00:00
if err := flushProfiling ( ) ; err != nil {
return err
}
if warningsAsErrors {
count := warningHandler . WarningCount ( )
switch count {
case 0 :
// no warnings
case 1 :
return fmt . Errorf ( "%d warning received" , count )
default :
return fmt . Errorf ( "%d warnings received" , count )
}
}
return nil
2019-01-12 04:58:27 +00:00
} ,
BashCompletionFunction : bashCompletionFunc ,
}
flags := cmds . PersistentFlags ( )
2019-04-07 17:07:55 +00:00
flags . SetNormalizeFunc ( cliflag . WarnWordSepNormalizeFunc ) // Warn for "_" flags
2019-01-12 04:58:27 +00:00
// Normalize all flags that are coming from other packages or pre-configurations
// a.k.a. change all "_" to "-". e.g. glog package
2019-04-07 17:07:55 +00:00
flags . SetNormalizeFunc ( cliflag . WordSepNormalizeFunc )
2019-01-12 04:58:27 +00:00
addProfilingFlags ( flags )
2020-08-10 17:43:49 +00:00
flags . BoolVar ( & warningsAsErrors , "warnings-as-errors" , warningsAsErrors , "Treat warnings received from the server as errors and exit with a non-zero exit code" )
2019-04-07 17:07:55 +00:00
kubeConfigFlags := genericclioptions . NewConfigFlags ( true ) . WithDeprecatedPasswordFlag ( )
2019-01-12 04:58:27 +00:00
kubeConfigFlags . AddFlags ( flags )
matchVersionKubeConfigFlags := cmdutil . NewMatchVersionFlags ( kubeConfigFlags )
matchVersionKubeConfigFlags . AddFlags ( cmds . PersistentFlags ( ) )
cmds . PersistentFlags ( ) . AddGoFlagSet ( flag . CommandLine )
f := cmdutil . NewFactory ( matchVersionKubeConfigFlags )
// Sending in 'nil' for the getLanguageFn() results in using
// the LANG environment variable.
//
// TODO: Consider adding a flag or file preference for setting
// the language, instead of just loading from the LANG env. variable.
i18n . LoadTranslations ( "kubectl" , nil )
// From this point and forward we get warnings on flags that contain "_" separators
2019-04-07 17:07:55 +00:00
cmds . SetGlobalNormalizationFunc ( cliflag . WarnWordSepNormalizeFunc )
2019-01-12 04:58:27 +00:00
ioStreams := genericclioptions . IOStreams { In : in , Out : out , ErrOut : err }
groups := templates . CommandGroups {
{
Message : "Basic Commands (Beginner):" ,
Commands : [ ] * cobra . Command {
create . NewCmdCreate ( f , ioStreams ) ,
expose . NewCmdExposeService ( f , ioStreams ) ,
run . NewCmdRun ( f , ioStreams ) ,
set . NewCmdSet ( f , ioStreams ) ,
} ,
} ,
{
Message : "Basic Commands (Intermediate):" ,
Commands : [ ] * cobra . Command {
2019-08-30 18:33:25 +00:00
explain . NewCmdExplain ( "kubectl" , f , ioStreams ) ,
2019-01-12 04:58:27 +00:00
get . NewCmdGet ( "kubectl" , f , ioStreams ) ,
edit . NewCmdEdit ( f , ioStreams ) ,
delete . NewCmdDelete ( f , ioStreams ) ,
} ,
} ,
{
Message : "Deploy Commands:" ,
Commands : [ ] * cobra . Command {
rollout . NewCmdRollout ( f , ioStreams ) ,
scale . NewCmdScale ( f , ioStreams ) ,
autoscale . NewCmdAutoscale ( f , ioStreams ) ,
} ,
} ,
{
Message : "Cluster Management Commands:" ,
Commands : [ ] * cobra . Command {
certificates . NewCmdCertificate ( f , ioStreams ) ,
clusterinfo . NewCmdClusterInfo ( f , ioStreams ) ,
top . NewCmdTop ( f , ioStreams ) ,
drain . NewCmdCordon ( f , ioStreams ) ,
drain . NewCmdUncordon ( f , ioStreams ) ,
drain . NewCmdDrain ( f , ioStreams ) ,
taint . NewCmdTaint ( f , ioStreams ) ,
} ,
} ,
{
Message : "Troubleshooting and Debugging Commands:" ,
Commands : [ ] * cobra . Command {
describe . NewCmdDescribe ( "kubectl" , f , ioStreams ) ,
logs . NewCmdLogs ( f , ioStreams ) ,
attach . NewCmdAttach ( f , ioStreams ) ,
cmdexec . NewCmdExec ( f , ioStreams ) ,
portforward . NewCmdPortForward ( f , ioStreams ) ,
proxy . NewCmdProxy ( f , ioStreams ) ,
cp . NewCmdCp ( f , ioStreams ) ,
auth . NewCmdAuth ( f , ioStreams ) ,
2020-12-01 01:06:26 +00:00
debug . NewCmdDebug ( f , ioStreams , false ) ,
2019-01-12 04:58:27 +00:00
} ,
} ,
{
Message : "Advanced Commands:" ,
Commands : [ ] * cobra . Command {
2019-08-30 18:33:25 +00:00
diff . NewCmdDiff ( f , ioStreams ) ,
2019-01-12 04:58:27 +00:00
apply . NewCmdApply ( "kubectl" , f , ioStreams ) ,
patch . NewCmdPatch ( f , ioStreams ) ,
replace . NewCmdReplace ( f , ioStreams ) ,
wait . NewCmdWait ( f , ioStreams ) ,
2019-08-30 18:33:25 +00:00
kustomize . NewCmdKustomize ( ioStreams ) ,
2019-01-12 04:58:27 +00:00
} ,
} ,
{
Message : "Settings Commands:" ,
Commands : [ ] * cobra . Command {
label . NewCmdLabel ( f , ioStreams ) ,
annotate . NewCmdAnnotate ( "kubectl" , f , ioStreams ) ,
completion . NewCmdCompletion ( ioStreams . Out , "" ) ,
} ,
} ,
}
groups . Add ( cmds )
filters := [ ] string { "options" }
// Hide the "alpha" subcommand if there are no alpha commands in this build.
2020-12-01 01:06:26 +00:00
alpha := NewCmdAlpha ( f , ioStreams )
2019-01-12 04:58:27 +00:00
if ! alpha . HasSubCommands ( ) {
filters = append ( filters , alpha . Name ( ) )
}
templates . ActsAsRootCommand ( cmds , filters , groups ... )
for name , completion := range bashCompletionFlags {
if cmds . Flag ( name ) != nil {
if cmds . Flag ( name ) . Annotations == nil {
cmds . Flag ( name ) . Annotations = map [ string ] [ ] string { }
}
cmds . Flag ( name ) . Annotations [ cobra . BashCompCustom ] = append (
cmds . Flag ( name ) . Annotations [ cobra . BashCompCustom ] ,
completion ,
)
}
}
cmds . AddCommand ( alpha )
cmds . AddCommand ( cmdconfig . NewCmdConfig ( f , clientcmd . NewDefaultPathOptions ( ) , ioStreams ) )
cmds . AddCommand ( plugin . NewCmdPlugin ( f , ioStreams ) )
cmds . AddCommand ( version . NewCmdVersion ( f , ioStreams ) )
cmds . AddCommand ( apiresources . NewCmdAPIVersions ( f , ioStreams ) )
cmds . AddCommand ( apiresources . NewCmdAPIResources ( f , ioStreams ) )
cmds . AddCommand ( options . NewCmdOptions ( ioStreams . Out ) )
return cmds
}
func runHelp ( cmd * cobra . Command , args [ ] string ) {
cmd . Help ( )
}