Move all completion bash code to Go code

Signed-off-by: Marc Khouzam <marc.khouzam@montreal.ca>
This commit is contained in:
Marc Khouzam 2021-03-05 15:43:31 -05:00
parent 663b13e814
commit 879cdc5fa9
38 changed files with 585 additions and 397 deletions

View File

@ -35,6 +35,8 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/apiresources"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/polymorphichelpers"
"k8s.io/kubectl/pkg/scheme"
@ -134,6 +136,15 @@ func NewCmdAnnotate(parent string, f cmdutil.Factory, ioStreams genericclioption
Short: i18n.T("Update the annotations on a resource"),
Long: annotateLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
Example: annotateExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())

View File

@ -17,8 +17,11 @@ limitations under the License.
package apiresources
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"sort"
"strings"
@ -275,3 +278,38 @@ func (s sortableResource) compareValues(i, j int) (string, string) {
}
return s.resources[i].APIGroup, s.resources[j].APIGroup
}
// CompGetResourceList returns the list of api resources which begin with `toComplete`.
func CompGetResourceList(f cmdutil.Factory, cmd *cobra.Command, toComplete string) []string {
buf := new(bytes.Buffer)
streams := genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: ioutil.Discard}
o := NewAPIResourceOptions(streams)
// Get the list of resources
o.Output = "name"
o.Cached = true
o.Verbs = []string{"get"}
// TODO:Should set --request-timeout=5s
// Ignore errors as the output may still be valid
o.RunAPIResources(cmd, f)
// Resources can be a comma-separated list. The last element is then
// the one we should complete. For example if toComplete=="pods,secre"
// we should return "pods,secrets"
prefix := ""
suffix := toComplete
lastIdx := strings.LastIndex(toComplete, ",")
if lastIdx != -1 {
prefix = toComplete[0 : lastIdx+1]
suffix = toComplete[lastIdx+1:]
}
var comps []string
resources := strings.Split(buf.String(), "\n")
for _, res := range resources {
if res != "" && strings.HasPrefix(res, suffix) {
comps = append(comps, fmt.Sprintf("%s%s", prefix, res))
}
}
return comps
}

View File

@ -20,6 +20,8 @@ import (
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/kubectl/pkg/cmd/apiresources"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/cmd/util/editor"
"k8s.io/kubectl/pkg/util/i18n"
@ -66,6 +68,15 @@ func NewCmdApplyEditLastApplied(f cmdutil.Factory, ioStreams genericclioptions.I
Short: i18n.T("Edit latest last-applied-configuration annotations of a resource/object"),
Long: applyEditLastAppliedLong,
Example: applyEditLastAppliedExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, args, cmd))
cmdutil.CheckErr(o.Run())

View File

@ -24,6 +24,8 @@ import (
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/apiresources"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/util"
"k8s.io/kubectl/pkg/util/i18n"
@ -77,6 +79,15 @@ func NewCmdApplyViewLastApplied(f cmdutil.Factory, ioStreams genericclioptions.I
Short: i18n.T("View latest last-applied-configuration annotations of a resource/object"),
Long: applyViewLastAppliedLong,
Example: applyViewLastAppliedExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(cmd, f, args))
cmdutil.CheckErr(options.Validate(cmd))

View File

@ -31,6 +31,7 @@ import (
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/remotecommand"
"k8s.io/kubectl/pkg/cmd/exec"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/cmd/util/podcmd"
"k8s.io/kubectl/pkg/polymorphichelpers"
@ -104,6 +105,13 @@ func NewCmdAttach(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra
Short: i18n.T("Attach to a running container"),
Long: i18n.T("Attach to a process that is already running inside an existing container."),
Example: attachExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = get.CompGetResource(f, cmd, "pod", toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())

View File

@ -19,6 +19,7 @@ package autoscale
import (
"context"
"fmt"
"strings"
"github.com/spf13/cobra"
"k8s.io/klog/v2"
@ -31,6 +32,7 @@ import (
"k8s.io/cli-runtime/pkg/resource"
autoscalingv1client "k8s.io/client-go/kubernetes/typed/autoscaling/v1"
"k8s.io/client-go/scale"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util"
@ -107,12 +109,24 @@ func NewCmdAutoscale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *
Short: i18n.T("Auto-scale a Deployment, ReplicaSet, StatefulSet, or ReplicationController"),
Long: autoscaleLong,
Example: autoscaleExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
for _, comp := range validArgs {
if strings.HasPrefix(comp, toComplete) {
comps = append(comps, comp)
}
}
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run())
},
ValidArgs: validArgs,
}
// bind flag structs

View File

@ -79,250 +79,6 @@ import (
"k8s.io/kubectl/pkg/cmd/kustomize"
)
const (
bashCompletionFunc = `# call kubectl get $1,
__kubectl_debug_out()
{
local cmd="$1"
__kubectl_debug "${FUNCNAME[1]}: get completion by ${cmd}"
eval "${cmd} 2>/dev/null"
}
__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
eval "echo -n \${${var}}' '"
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 }}"
if kubectl_out=$(__kubectl_debug_out "kubectl config $(__kubectl_override_flags) -o template --template=\"${template}\" view"); then
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
if kubectl_out=$(__kubectl_debug_out "kubectl get $(__kubectl_override_flags) -o template --template=\"${template}\" \"$1\""); then
COMPREPLY+=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
fi
}
# Same as __kubectl_get_resources (with s) but allows completion for only one resource name.
__kubectl_get_resource()
{
if [[ ${#nouns[@]} -eq 0 ]]; then
__kubectl_get_resource_helper "" "$cur"
return # the return status is that of the last command executed in the function body
fi
__kubectl_parse_get "${nouns[${#nouns[@]} -1]}"
}
# Same as __kubectl_get_resource (without s) but allows completion for multiple, comma-separated resource names.
__kubectl_get_resources()
{
local SEPARATOR=','
if [[ ${#nouns[@]} -eq 0 ]]; then
local kubectl_out HEAD TAIL
HEAD=""
TAIL="$cur"
# if SEPARATOR is contained in $cur, e.g. "pod,sec"
if [[ "$cur" = *${SEPARATOR}* ]] ; then
# set HEAD to "pod,"
HEAD="${cur%${SEPARATOR}*}${SEPARATOR}"
# set TAIL to "sec"
TAIL="${cur##*${SEPARATOR}}"
fi
__kubectl_get_resource_helper "$HEAD" "$TAIL"
return # the return status is that of the last command executed in the function body
fi
__kubectl_parse_get "${nouns[${#nouns[@]} -1]}"
}
__kubectl_get_resource_helper()
{
local kubectl_out HEAD TAIL
HEAD="$1"
TAIL="$2"
if kubectl_out=$(__kubectl_debug_out "kubectl api-resources $(__kubectl_override_flags) -o name --cached --request-timeout=5s --verbs=get"); then
COMPREPLY=( $( compgen -P "$HEAD" -W "${kubectl_out[*]}" -- "$TAIL" ) )
return 0
fi
return 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
if kubectl_out=$(__kubectl_debug_out "kubectl get $(__kubectl_override_flags) -o template --template=\"${template}\" pods \"${last}\""); then
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%%/*}"
if kubectl_out=$(__kubectl_debug_out "kubectl get $(__kubectl_override_flags) --namespace \"${namespace}\" -o template --template=\"${template}\" pods"); then
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
}
__kubectl_custom_func() {
case ${last_command} in
kubectl_get)
__kubectl_get_resources
return
;;
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
;;
kubectl_logs)
__kubectl_require_pod_and_container
return
;;
kubectl_exec | kubectl_port-forward | kubectl_top_pod | kubectl_attach)
__kubectl_get_resource_pod
return
;;
kubectl_cordon | kubectl_uncordon | kubectl_drain | kubectl_top_node)
__kubectl_get_resource_node
return
;;
kubectl_config_use-context | kubectl_config_rename-context | kubectl_config_delete-context)
__kubectl_config_get_contexts
return
;;
kubectl_config_delete-cluster)
__kubectl_config_get_clusters
return
;;
kubectl_cp)
__kubectl_cp
return
;;
*)
;;
esac
}
`
)
const kubectlCmdHeaders = "KUBECTL_COMMAND_HEADERS"
// NewDefaultKubectlCommand creates the `kubectl` command with default arguments
@ -496,7 +252,6 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
}
return nil
},
BashCompletionFunction: bashCompletionFunc,
}
flags := cmds.PersistentFlags()
@ -672,3 +427,26 @@ func addCmdHeaderHooks(cmds *cobra.Command, kubeConfigFlags *genericclioptions.C
func runHelp(cmd *cobra.Command, args []string) {
cmd.Help()
}
func registerCompletionFuncForGlobalFlags(cmd *cobra.Command, f cmdutil.Factory) {
cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc(
"namespace",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return get.CompGetResource(f, cmd, "namespace", toComplete), cobra.ShellCompDirectiveNoFileComp
}))
cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc(
"context",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return cmdconfig.CompListContextsInConfig(nil, toComplete), cobra.ShellCompDirectiveNoFileComp
}))
cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc(
"cluster",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return cmdconfig.CompListClustersInConfig(nil, toComplete), cobra.ShellCompDirectiveNoFileComp
}))
cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc(
"user",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return cmdconfig.CompListUsersInConfig(nil, toComplete), cobra.ShellCompDirectiveNoFileComp
}))
}

View File

@ -1,46 +0,0 @@
/*
Copyright 2021 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 (
"github.com/spf13/cobra"
"k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/completion"
)
func registerCompletionFuncForGlobalFlags(cmd *cobra.Command, f util.Factory) {
util.CheckErr(cmd.RegisterFlagCompletionFunc(
"namespace",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completion.ListNamespaces(f, toComplete)
}))
util.CheckErr(cmd.RegisterFlagCompletionFunc(
"context",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completion.ListContextsInKubeconfig(f, toComplete)
}))
util.CheckErr(cmd.RegisterFlagCompletionFunc(
"cluster",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completion.ListClustersInKubeconfig(f, toComplete)
}))
util.CheckErr(cmd.RegisterFlagCompletionFunc(
"user",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return completion.ListUsersInKubeconfig(f, toComplete)
}))
}

View File

@ -20,6 +20,7 @@ import (
"fmt"
"path"
"strconv"
"strings"
"github.com/spf13/cobra"
@ -30,8 +31,22 @@ import (
"k8s.io/kubectl/pkg/util/templates"
)
var (
// CompListContextsInConfig returns a list of context names which begin with `toComplete`
// We allow to pass in a factory to be ready for a future improvement
CompListContextsInConfig func(f cmdutil.Factory, toComplete string) []string
// CompListClustersInConfig returns a list of cluster names which begin with `toComplete`
// We allow to pass in a factory to be ready for a future improvement
CompListClustersInConfig func(f cmdutil.Factory, toComplete string) []string
// CompListUsersInConfig returns a list of user names which begin with `toComplete`
// We allow to pass in a factory to be ready for a future improvement
CompListUsersInConfig func(f cmdutil.Factory, toComplete string) []string
)
// NewCmdConfig creates a command object for the "config" action, and adds all child commands to it.
func NewCmdConfig(f cmdutil.Factory, pathOptions *clientcmd.PathOptions, streams genericclioptions.IOStreams) *cobra.Command {
initCompletionFunctions(f)
if len(pathOptions.ExplicitFileFlag) == 0 {
pathOptions.ExplicitFileFlag = clientcmd.RecommendedConfigPathFlag
}
@ -92,3 +107,48 @@ func helpErrorf(cmd *cobra.Command, format string, args ...interface{}) error {
msg := fmt.Sprintf(format, args...)
return fmt.Errorf("%s", msg)
}
// The completion function need the factory, so we initialize them once it is available
func initCompletionFunctions(f cmdutil.Factory) {
CompListContextsInConfig = func(notused cmdutil.Factory, toComplete string) []string {
config, err := f.ToRawKubeConfigLoader().RawConfig()
if err != nil {
return nil
}
var ret []string
for name := range config.Contexts {
if strings.HasPrefix(name, toComplete) {
ret = append(ret, name)
}
}
return ret
}
CompListClustersInConfig = func(notused cmdutil.Factory, toComplete string) []string {
config, err := f.ToRawKubeConfigLoader().RawConfig()
if err != nil {
return nil
}
var ret []string
for name := range config.Clusters {
if strings.HasPrefix(name, toComplete) {
ret = append(ret, name)
}
}
return ret
}
CompListUsersInConfig = func(notused cmdutil.Factory, toComplete string) []string {
config, err := f.ToRawKubeConfigLoader().RawConfig()
if err != nil {
return nil
}
var ret []string
for name := range config.AuthInfos {
if strings.HasPrefix(name, toComplete) {
ret = append(ret, name)
}
}
return ret
}
}

View File

@ -41,6 +41,12 @@ func NewCmdConfigDeleteCluster(out io.Writer, configAccess clientcmd.ConfigAcces
Short: i18n.T("Delete the specified cluster from the kubeconfig"),
Long: i18n.T("Delete the specified cluster from the kubeconfig"),
Example: deleteClusterExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 {
return CompListClustersInConfig(nil, toComplete), cobra.ShellCompDirectiveNoFileComp
}
return nil, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(runDeleteCluster(out, configAccess, cmd))
},

View File

@ -41,6 +41,12 @@ func NewCmdConfigDeleteContext(out, errOut io.Writer, configAccess clientcmd.Con
Short: i18n.T("Delete the specified context from the kubeconfig"),
Long: i18n.T("Delete the specified context from the kubeconfig"),
Example: deleteContextExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 {
return CompListContextsInConfig(nil, toComplete), cobra.ShellCompDirectiveNoFileComp
}
return nil, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(runDeleteContext(out, errOut, configAccess, cmd))
},

View File

@ -67,6 +67,12 @@ func NewCmdConfigRenameContext(out io.Writer, configAccess clientcmd.ConfigAcces
Short: renameContextShort,
Long: renameContextLong,
Example: renameContextExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 {
return CompListContextsInConfig(nil, toComplete), cobra.ShellCompDirectiveNoFileComp
}
return nil, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(cmd, args, out))
cmdutil.CheckErr(options.Validate())

View File

@ -52,6 +52,12 @@ func NewCmdConfigUseContext(out io.Writer, configAccess clientcmd.ConfigAccess)
Aliases: []string{"use"},
Long: `Sets the current-context in a kubeconfig file`,
Example: useContextExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) == 0 {
return CompListContextsInConfig(nil, toComplete), cobra.ShellCompDirectiveNoFileComp
}
return nil, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.complete(cmd))
cmdutil.CheckErr(options.run())

View File

@ -35,6 +35,7 @@ import (
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
"k8s.io/kubectl/pkg/cmd/exec"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
@ -104,6 +105,57 @@ func NewCmdCp(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.C
Short: i18n.T("Copy files and directories to and from containers."),
Long: i18n.T("Copy files and directories to and from containers."),
Example: cpExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
if strings.IndexAny(toComplete, "/.~") == 0 {
// Looks like a path, do nothing
} else if strings.Index(toComplete, ":") != -1 {
// TODO: complete remote files in the pod
} else if idx := strings.Index(toComplete, "/"); idx > 0 {
// complete <namespace>/<pod>
namespace := toComplete[:idx]
template := "{{ range .items }}{{ .metadata.namespace }}/{{ .metadata.name }}: {{ end }}"
comps = get.CompGetFromTemplate(&template, f, namespace, cmd, []string{"pod"}, toComplete)
} else {
// Complete namespaces followed by a /
for _, ns := range get.CompGetResource(f, cmd, "namespace", toComplete) {
comps = append(comps, fmt.Sprintf("%s/", ns))
}
// Complete pod names followed by a :
for _, pod := range get.CompGetResource(f, cmd, "pod", toComplete) {
comps = append(comps, fmt.Sprintf("%s:", pod))
}
// Finally, provide file completion if we need to.
// We only do this if:
// 1- There are other completions found (if there are no completions,
// the shell will do file completion itself)
// 2- If there is some input from the user (or else we will end up
// listing the entire content of the current directory which could
// be too many choices for the user)
if len(comps) > 0 && len(toComplete) > 0 {
if files, err := ioutil.ReadDir("."); err == nil {
for _, file := range files {
filename := file.Name()
if strings.HasPrefix(filename, toComplete) {
if file.IsDir() {
filename = fmt.Sprintf("%s/", filename)
}
// We are completing a file prefix
comps = append(comps, filename)
}
}
}
} else if len(toComplete) == 0 {
// If the user didn't provide any input to complete,
// we provide a hint that a path can also be used
comps = append(comps, "./", "/")
}
}
}
return comps, cobra.ShellCompDirectiveNoSpace
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd))
cmdutil.CheckErr(o.Run(args))

View File

@ -29,6 +29,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/resource"
rbacclientv1 "k8s.io/client-go/kubernetes/typed/rbac/v1"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util"
@ -99,11 +100,18 @@ func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, ioStreams genericclioptio
cmdutil.AddDryRunFlag(cmd)
cmd.Flags().StringVar(&o.ClusterRole, "clusterrole", "", i18n.T("ClusterRole this ClusterRoleBinding should reference"))
cmd.MarkFlagRequired("clusterrole")
cmd.MarkFlagCustom("clusterrole", "__kubectl_get_resource_clusterrole")
cmd.Flags().StringArrayVar(&o.Users, "user", o.Users, "Usernames to bind to the clusterrole")
cmd.Flags().StringArrayVar(&o.Groups, "group", o.Groups, "Groups to bind to the clusterrole")
cmd.Flags().StringArrayVar(&o.ServiceAccounts, "serviceaccount", o.ServiceAccounts, "Service accounts to bind to the clusterrole, in the format <namespace>:<name>")
cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create")
// Completion for relevant flags
cmdutil.CheckErr(cmd.RegisterFlagCompletionFunc(
"clusterrole",
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return get.CompGetResource(f, cmd, "clusterrole", toComplete), cobra.ShellCompDirectiveNoFileComp
}))
return cmd
}

View File

@ -33,6 +33,8 @@ import (
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/client-go/dynamic"
"k8s.io/kubectl/pkg/cmd/apiresources"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
cmdwait "k8s.io/kubectl/pkg/cmd/wait"
"k8s.io/kubectl/pkg/rawhttp"
@ -135,6 +137,15 @@ func NewCmdDelete(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra
Short: i18n.T("Delete resources by filenames, stdin, resources and names, or by resources and label selector"),
Long: deleteLong,
Example: deleteExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
o, err := deleteFlags.ToOptions(nil, streams)
cmdutil.CheckErr(err)

View File

@ -28,6 +28,8 @@ import (
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/apiresources"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/describe"
"k8s.io/kubectl/pkg/util/i18n"
@ -106,6 +108,15 @@ func NewCmdDescribe(parent string, f cmdutil.Factory, streams genericclioptions.
Short: i18n.T("Show details of a specific resource or group of resources"),
Long: describeLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
Example: describeExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Run())

View File

@ -31,6 +31,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/drain"
"k8s.io/kubectl/pkg/scheme"
@ -68,6 +69,13 @@ func NewCmdCordon(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cob
Short: i18n.T("Mark node as unschedulable"),
Long: cordonLong,
Example: cordonExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = get.CompGetResource(f, cmd, "node", toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.RunCordonOrUncordon(true))
@ -96,6 +104,13 @@ func NewCmdUncordon(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *c
Short: i18n.T("Mark node as schedulable"),
Long: uncordonLong,
Example: uncordonExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = get.CompGetResource(f, cmd, "node", toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.RunCordonOrUncordon(false))
@ -181,6 +196,13 @@ func NewCmdDrain(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobr
Short: i18n.T("Drain node in preparation for maintenance"),
Long: drainLong,
Example: drainExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = get.CompGetResource(f, cmd, "node", toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.RunDrain())

View File

@ -20,6 +20,8 @@ import (
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/kubectl/pkg/cmd/apiresources"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/cmd/util/editor"
"k8s.io/kubectl/pkg/util/i18n"
@ -76,6 +78,15 @@ func NewCmdEdit(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra
Short: i18n.T("Edit a resource on the server"),
Long: editLong,
Example: editExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, args, cmd))
cmdutil.CheckErr(o.Run())

View File

@ -33,6 +33,7 @@ import (
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/remotecommand"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/cmd/util/podcmd"
"k8s.io/kubectl/pkg/polymorphichelpers"
@ -88,6 +89,13 @@ func NewCmdExec(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
Short: i18n.T("Execute a command in a container"),
Long: i18n.T("Execute a command in a container."),
Example: execExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = get.CompGetResource(f, cmd, "pod", toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
argsLenAtDash := cmd.ArgsLenAtDash()
cmdutil.CheckErr(options.Complete(f, cmd, args, argsLenAtDash))

View File

@ -31,6 +31,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/generate"
generateversioned "k8s.io/kubectl/pkg/generate/versioned"
@ -134,11 +135,23 @@ func NewCmdExposeService(f cmdutil.Factory, streams genericclioptions.IOStreams)
Short: i18n.T("Take a replication controller, service, deployment or pod and expose it as a new Kubernetes Service"),
Long: exposeLong,
Example: exposeExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
for _, comp := range validArgs {
if strings.HasPrefix(comp, toComplete) {
comps = append(comps, comp)
}
}
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd))
cmdutil.CheckErr(o.RunExpose(cmd, args))
},
ValidArgs: validArgs,
}
o.RecordFlags.AddFlags(cmd)

View File

@ -17,11 +17,14 @@ limitations under the License.
package get
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"net/url"
"os"
"strings"
"github.com/spf13/cobra"
@ -42,6 +45,7 @@ import (
kubernetesscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
watchtools "k8s.io/client-go/tools/watch"
"k8s.io/kubectl/pkg/cmd/apiresources"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/rawhttp"
"k8s.io/kubectl/pkg/scheme"
@ -161,6 +165,15 @@ func NewCmdGet(parent string, f cmdutil.Factory, streams genericclioptions.IOStr
Short: i18n.T("Display one or many resources"),
Long: getLong + "\n\n" + cmdutil.SuggestAPIResources(parent),
Example: getExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
} else if len(args) == 1 {
comps = CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate(cmd))
@ -849,3 +862,61 @@ func multipleGVKsRequested(infos []*resource.Info) bool {
}
return false
}
// CompGetResource gets the list of the resource specified which begin with `toComplete`.
func CompGetResource(f cmdutil.Factory, cmd *cobra.Command, resourceName string, toComplete string) []string {
template := "{{ range .items }}{{ .metadata.name }} {{ end }}"
return CompGetFromTemplate(&template, f, "", cmd, []string{resourceName}, toComplete)
}
// CompGetContainers gets the list of containers of the specified pod which begin with `toComplete`.
func CompGetContainers(f cmdutil.Factory, cmd *cobra.Command, podName string, toComplete string) []string {
template := "{{ range .spec.initContainers }}{{ .name }} {{end}}{{ range .spec.containers }}{{ .name }} {{ end }}"
return CompGetFromTemplate(&template, f, "", cmd, []string{"pod", podName}, toComplete)
}
// CompGetFromTemplate executes a Get operation using the specified template and args and returns the results
// which begin with `toComplete`.
func CompGetFromTemplate(template *string, f cmdutil.Factory, namespace string, cmd *cobra.Command, args []string, toComplete string) []string {
buf := new(bytes.Buffer)
streams := genericclioptions.IOStreams{In: os.Stdin, Out: buf, ErrOut: ioutil.Discard}
o := NewGetOptions("kubectl", streams)
// Get the list of names of the specified resource
o.PrintFlags.TemplateFlags.GoTemplatePrintFlags.TemplateArgument = template
format := "go-template"
o.PrintFlags.OutputFormat = &format
// Do the steps Complete() would have done.
// We cannot actually call Complete() or Validate() as these function check for
// the presence of flags, which, in our case won't be there
if namespace != "" {
o.Namespace = namespace
o.ExplicitNamespace = true
} else {
var err error
o.Namespace, o.ExplicitNamespace, err = f.ToRawKubeConfigLoader().Namespace()
if err != nil {
return nil
}
}
o.ToPrinter = func(mapping *meta.RESTMapping, outputObjects *bool, withNamespace bool, withKind bool) (printers.ResourcePrinterFunc, error) {
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
return nil, err
}
return printer.PrintObj, nil
}
o.Run(f, cmd, args)
var comps []string
resources := strings.Split(buf.String(), " ")
for _, res := range resources {
if res != "" && strings.HasPrefix(res, toComplete) {
comps = append(comps, res)
}
}
return comps
}

View File

@ -37,6 +37,8 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/apiresources"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util/i18n"
@ -132,6 +134,15 @@ func NewCmdLabel(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobr
Short: i18n.T("Update the labels on a resource"),
Long: fmt.Sprintf(labelLong, validation.LabelValueMaxLength),
Example: labelExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())

View File

@ -33,6 +33,7 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/polymorphichelpers"
"k8s.io/kubectl/pkg/scheme"
@ -152,6 +153,15 @@ func NewCmdLogs(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
Short: i18n.T("Print the logs for a container in a pod"),
Long: logsLong,
Example: logsExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = get.CompGetResource(f, cmd, "pod", toComplete)
} else if len(args) == 1 {
comps = get.CompGetContainers(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())

View File

@ -37,6 +37,8 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/apiresources"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util/i18n"
@ -114,6 +116,15 @@ func NewCmdPatch(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobr
Short: i18n.T("Update field(s) of a resource"),
Long: patchLong,
Example: patchExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = apiresources.CompGetResourceList(f, cmd, toComplete)
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())

View File

@ -38,6 +38,7 @@ import (
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/portforward"
"k8s.io/client-go/transport/spdy"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/polymorphichelpers"
"k8s.io/kubectl/pkg/util"
@ -109,6 +110,13 @@ func NewCmdPortForward(f cmdutil.Factory, streams genericclioptions.IOStreams) *
Short: i18n.T("Forward one or more local ports to a pod"),
Long: portforwardLong,
Example: portforwardExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = get.CompGetResource(f, cmd, "pod", toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(opts.Complete(f, cmd, args))
cmdutil.CheckErr(opts.Validate())

View File

@ -18,12 +18,14 @@ package rollout
import (
"fmt"
"strings"
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/polymorphichelpers"
"k8s.io/kubectl/pkg/scheme"
@ -82,12 +84,24 @@ func NewCmdRolloutHistory(f cmdutil.Factory, streams genericclioptions.IOStreams
Short: i18n.T("View rollout history"),
Long: historyLong,
Example: historyExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
for _, comp := range validArgs {
if strings.HasPrefix(comp, toComplete) {
comps = append(comps, comp)
}
}
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run())
},
ValidArgs: validArgs,
}
cmd.Flags().Int64Var(&o.Revision, "revision", o.Revision, "See the details, including podTemplate of the revision specified")

View File

@ -18,6 +18,7 @@ package rollout
import (
"fmt"
"strings"
"github.com/spf13/cobra"
@ -26,6 +27,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/get"
"k8s.io/kubectl/pkg/cmd/set"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/polymorphichelpers"
@ -82,12 +84,24 @@ func NewCmdRolloutPause(f cmdutil.Factory, streams genericclioptions.IOStreams)
Short: i18n.T("Mark the provided resource as paused"),
Long: pauseLong,
Example: pauseExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
for _, comp := range validArgs {
if strings.HasPrefix(comp, toComplete) {
comps = append(comps, comp)
}
}
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunPause())
},
ValidArgs: validArgs,
}
o.PrintFlags.AddFlags(cmd)

View File

@ -18,6 +18,7 @@ package rollout
import (
"fmt"
"strings"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/types"
@ -25,6 +26,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/get"
"k8s.io/kubectl/pkg/cmd/set"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/polymorphichelpers"
@ -86,12 +88,24 @@ func NewCmdRolloutRestart(f cmdutil.Factory, streams genericclioptions.IOStreams
Short: i18n.T("Restart a resource"),
Long: restartLong,
Example: restartExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
for _, comp := range validArgs {
if strings.HasPrefix(comp, toComplete) {
comps = append(comps, comp)
}
}
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunRestart())
},
ValidArgs: validArgs,
}
usage := "identifying the resource to get from a server."

View File

@ -18,6 +18,7 @@ package rollout
import (
"fmt"
"strings"
"github.com/spf13/cobra"
@ -26,6 +27,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/get"
"k8s.io/kubectl/pkg/cmd/set"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/polymorphichelpers"
@ -86,12 +88,24 @@ func NewCmdRolloutResume(f cmdutil.Factory, streams genericclioptions.IOStreams)
Short: i18n.T("Resume a paused resource"),
Long: resumeLong,
Example: resumeExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
for _, comp := range validArgs {
if strings.HasPrefix(comp, toComplete) {
comps = append(comps, comp)
}
}
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunResume())
},
ValidArgs: validArgs,
}
usage := "identifying the resource to get from a server."

View File

@ -19,6 +19,7 @@ package rollout
import (
"context"
"fmt"
"strings"
"time"
"github.com/spf13/cobra"
@ -34,6 +35,7 @@ import (
"k8s.io/client-go/dynamic"
"k8s.io/client-go/tools/cache"
watchtools "k8s.io/client-go/tools/watch"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/polymorphichelpers"
"k8s.io/kubectl/pkg/scheme"
@ -101,12 +103,24 @@ func NewCmdRolloutStatus(f cmdutil.Factory, streams genericclioptions.IOStreams)
Short: i18n.T("Show the status of the rollout"),
Long: statusLong,
Example: statusExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
for _, comp := range validArgs {
if strings.HasPrefix(comp, toComplete) {
comps = append(comps, comp)
}
}
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.Run())
},
ValidArgs: validArgs,
}
usage := "identifying the resource to get from a server."

View File

@ -18,12 +18,14 @@ package rollout
import (
"fmt"
"strings"
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/polymorphichelpers"
"k8s.io/kubectl/pkg/scheme"
@ -86,12 +88,24 @@ func NewCmdRolloutUndo(f cmdutil.Factory, streams genericclioptions.IOStreams) *
Short: i18n.T("Undo a previous rollout"),
Long: undoLong,
Example: undoExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
for _, comp := range validArgs {
if strings.HasPrefix(comp, toComplete) {
comps = append(comps, comp)
}
}
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunUndo())
},
ValidArgs: validArgs,
}
cmd.Flags().Int64Var(&o.ToRevision, "to-revision", o.ToRevision, "The revision to rollback to. Default to 0 (last revision).")

View File

@ -18,6 +18,7 @@ package scale
import (
"fmt"
"strings"
"time"
"github.com/spf13/cobra"
@ -29,6 +30,7 @@ import (
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/client-go/kubernetes"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scale"
"k8s.io/kubectl/pkg/util/i18n"
@ -113,12 +115,24 @@ func NewCmdScale(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobr
Short: i18n.T("Set a new size for a Deployment, ReplicaSet or Replication Controller"),
Long: scaleLong,
Example: scaleExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
for _, comp := range validArgs {
if strings.HasPrefix(comp, toComplete) {
comps = append(comps, comp)
}
}
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate(cmd))
cmdutil.CheckErr(o.RunScale())
},
ValidArgs: validArgs,
}
o.RecordFlags.AddFlags(cmd)

View File

@ -35,6 +35,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util/i18n"
@ -108,12 +109,24 @@ func NewCmdTaint(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.
Short: i18n.T("Update the taints on one or more nodes"),
Long: fmt.Sprintf(taintLong, validation.DNS1123SubdomainMaxLength, validation.LabelValueMaxLength),
Example: taintExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
for _, comp := range validArgs {
if strings.HasPrefix(comp, toComplete) {
comps = append(comps, comp)
}
}
} else if len(args) == 1 {
comps = get.CompGetResource(f, cmd, args[0], toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.Complete(f, cmd, args))
cmdutil.CheckErr(options.Validate())
cmdutil.CheckErr(options.RunTaint())
},
ValidArgs: validArgs,
}
options.PrintFlags.AddFlags(cmd)

View File

@ -27,6 +27,7 @@ import (
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/discovery"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/metricsutil"
"k8s.io/kubectl/pkg/util/i18n"
@ -80,6 +81,13 @@ func NewCmdTopNode(f cmdutil.Factory, o *TopNodeOptions, streams genericclioptio
Short: i18n.T("Display Resource (CPU/Memory) usage of nodes"),
Long: topNodeLong,
Example: topNodeExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = get.CompGetResource(f, cmd, "node", toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())

View File

@ -27,6 +27,7 @@ import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/discovery"
corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/kubectl/pkg/cmd/get"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/metricsutil"
"k8s.io/kubectl/pkg/util/i18n"
@ -97,6 +98,13 @@ func NewCmdTopPod(f cmdutil.Factory, o *TopPodOptions, streams genericclioptions
Short: i18n.T("Display Resource (CPU/Memory) usage of pods"),
Long: topPodLong,
Example: topPodExample,
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
var comps []string
if len(args) == 0 {
comps = get.CompGetResource(f, cmd, "pod", toComplete)
}
return comps, cobra.ShellCompDirectiveNoFileComp
},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())

View File

@ -1,94 +0,0 @@
/*
Copyright 2021 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 completion
import (
"context"
"strings"
"time"
"github.com/spf13/cobra"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubectl/pkg/cmd/util"
)
// ListNamespaces returns a list of namespaces which begins with `toComplete`.
func ListNamespaces(f util.Factory, toComplete string) ([]string, cobra.ShellCompDirective) {
clientSet, err := f.KubernetesClientSet()
if err != nil {
return nil, cobra.ShellCompDirectiveDefault
}
ctx, cancel := context.WithTimeout(context.TODO(), time.Second*3)
defer cancel()
namespaces, err := clientSet.CoreV1().Namespaces().List(ctx, metav1.ListOptions{})
if err != nil {
return nil, cobra.ShellCompDirectiveDefault
}
var ret []string
for _, ns := range namespaces.Items {
if strings.HasPrefix(ns.Name, toComplete) {
ret = append(ret, ns.Name)
}
}
return ret, cobra.ShellCompDirectiveNoFileComp
}
// ListContextsInKubeconfig returns a list of context names which begins with `toComplete`.
func ListContextsInKubeconfig(f util.Factory, toComplete string) ([]string, cobra.ShellCompDirective) {
config, err := f.ToRawKubeConfigLoader().RawConfig()
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
var ret []string
for name := range config.Contexts {
if strings.HasPrefix(name, toComplete) {
ret = append(ret, name)
}
}
return ret, cobra.ShellCompDirectiveNoFileComp
}
// ListClustersInKubeconfig returns a list of cluster names which begins with `toComplete`.
func ListClustersInKubeconfig(f util.Factory, toComplete string) ([]string, cobra.ShellCompDirective) {
config, err := f.ToRawKubeConfigLoader().RawConfig()
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
var ret []string
for name := range config.Clusters {
if strings.HasPrefix(name, toComplete) {
ret = append(ret, name)
}
}
return ret, cobra.ShellCompDirectiveNoFileComp
}
// ListUsersInKubeconfig returns a list of user names which begins with `toComplete`.
func ListUsersInKubeconfig(f util.Factory, toComplete string) ([]string, cobra.ShellCompDirective) {
config, err := f.ToRawKubeConfigLoader().RawConfig()
if err != nil {
return nil, cobra.ShellCompDirectiveNoFileComp
}
var ret []string
for name := range config.AuthInfos {
if strings.HasPrefix(name, toComplete) {
ret = append(ret, name)
}
}
return ret, cobra.ShellCompDirectiveNoFileComp
}

1
vendor/modules.txt vendored
View File

@ -2070,7 +2070,6 @@ k8s.io/kubectl/pkg/cmd/util/podcmd
k8s.io/kubectl/pkg/cmd/util/sanity
k8s.io/kubectl/pkg/cmd/version
k8s.io/kubectl/pkg/cmd/wait
k8s.io/kubectl/pkg/completion
k8s.io/kubectl/pkg/describe
k8s.io/kubectl/pkg/drain
k8s.io/kubectl/pkg/explain