Commit 7e0bb885 authored by Dr. Stefan Schimanski's avatar Dr. Stefan Schimanski

Make kubectl bash completion namespace aware and add noun aliases

- add namespace filtering to bash completion - add --namespace flag bash completion - add bash completion noun aliases - adapt to new cobra package structure
parent 8af3be87
...@@ -21,7 +21,7 @@ import ( ...@@ -21,7 +21,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"github.com/spf13/cobra" "github.com/spf13/cobra/doc"
"k8s.io/kubernetes/cmd/genutils" "k8s.io/kubernetes/cmd/genutils"
"k8s.io/kubernetes/pkg/kubectl/cmd" "k8s.io/kubernetes/pkg/kubectl/cmd"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
...@@ -48,5 +48,5 @@ func main() { ...@@ -48,5 +48,5 @@ func main() {
os.Setenv("HOME", "/home/username") os.Setenv("HOME", "/home/username")
// TODO os.Stdin should really be something like ioutil.Discard, but a Reader // TODO os.Stdin should really be something like ioutil.Discard, but a Reader
kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard) kubectl := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, ioutil.Discard, ioutil.Discard)
cobra.GenMarkdownTree(kubectl, outDir) doc.GenMarkdownTree(kubectl, outDir)
} }
...@@ -20,7 +20,7 @@ import ( ...@@ -20,7 +20,7 @@ import (
"fmt" "fmt"
"os" "os"
"github.com/spf13/cobra" "github.com/spf13/cobra/doc"
"k8s.io/kubernetes/cmd/genutils" "k8s.io/kubernetes/cmd/genutils"
apiservapp "k8s.io/kubernetes/cmd/kube-apiserver/app" apiservapp "k8s.io/kubernetes/cmd/kube-apiserver/app"
cmapp "k8s.io/kubernetes/cmd/kube-controller-manager/app" cmapp "k8s.io/kubernetes/cmd/kube-controller-manager/app"
...@@ -51,23 +51,23 @@ func main() { ...@@ -51,23 +51,23 @@ func main() {
case "kube-apiserver": case "kube-apiserver":
// generate docs for kube-apiserver // generate docs for kube-apiserver
apiserver := apiservapp.NewAPIServerCommand() apiserver := apiservapp.NewAPIServerCommand()
cobra.GenMarkdownTree(apiserver, outDir) doc.GenMarkdownTree(apiserver, outDir)
case "kube-controller-manager": case "kube-controller-manager":
// generate docs for kube-controller-manager // generate docs for kube-controller-manager
controllermanager := cmapp.NewControllerManagerCommand() controllermanager := cmapp.NewControllerManagerCommand()
cobra.GenMarkdownTree(controllermanager, outDir) doc.GenMarkdownTree(controllermanager, outDir)
case "kube-proxy": case "kube-proxy":
// generate docs for kube-proxy // generate docs for kube-proxy
proxy := proxyapp.NewProxyCommand() proxy := proxyapp.NewProxyCommand()
cobra.GenMarkdownTree(proxy, outDir) doc.GenMarkdownTree(proxy, outDir)
case "kube-scheduler": case "kube-scheduler":
// generate docs for kube-scheduler // generate docs for kube-scheduler
scheduler := schapp.NewSchedulerCommand() scheduler := schapp.NewSchedulerCommand()
cobra.GenMarkdownTree(scheduler, outDir) doc.GenMarkdownTree(scheduler, outDir)
case "kubelet": case "kubelet":
// generate docs for kubelet // generate docs for kubelet
kubelet := kubeletapp.NewKubeletCommand() kubelet := kubeletapp.NewKubeletCommand()
cobra.GenMarkdownTree(kubelet, outDir) doc.GenMarkdownTree(kubelet, outDir)
default: default:
fmt.Fprintf(os.Stderr, "Module %s is not supported", module) fmt.Fprintf(os.Stderr, "Module %s is not supported", module)
os.Exit(1) os.Exit(1)
......
...@@ -30,12 +30,47 @@ import ( ...@@ -30,12 +30,47 @@ import (
const ( const (
bash_completion_func = `# call kubectl get $1, bash_completion_func = `# call kubectl get $1,
__kubectl_namespace_flag()
{
local ret two_word_ns
ret=""
two_word_ns=false
for w in "${words[@]}"; do
if [ "$two_word_ns" = true ]; then
ret="--namespace=${w}"
two_word_ns=false
continue
fi
case "${w}" in
--namespace=*)
ret=${w}
;;
--namespace)
two_word_ns=true
;;
--all-namespaces)
ret=${w}
;;
esac
done
echo $ret
}
__kubectl_get_namespaces()
{
local template kubectl_out
template="{{ range .items }}{{ .metadata.name }} {{ end }}"
if kubectl_out=$(kubectl get -o template --template="${template}" namespace 2>/dev/null); then
COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
fi
}
__kubectl_parse_get() __kubectl_parse_get()
{ {
local template local template
template="{{ range .items }}{{ .metadata.name }} {{ end }}" template="{{ range .items }}{{ .metadata.name }} {{ end }}"
local kubectl_out local kubectl_out
if kubectl_out=$(kubectl get -o template --template="${template}" "$1" 2>/dev/null); then if kubectl_out=$(kubectl get $(__kubectl_namespace_flag) -o template --template="${template}" "$1" 2>/dev/null); then
COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) ) COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
fi fi
} }
...@@ -71,7 +106,7 @@ __kubectl_get_containers() ...@@ -71,7 +106,7 @@ __kubectl_get_containers()
fi fi
local last=${nouns[${len} -1]} local last=${nouns[${len} -1]}
local kubectl_out local kubectl_out
if kubectl_out=$(kubectl get -o template --template="${template}" pods "${last}" 2>/dev/null); then if kubectl_out=$(kubectl get $(__kubectl_namespace_flag) -o template --template="${template}" pods "${last}" 2>/dev/null); then
COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) ) COMPREPLY=( $( compgen -W "${kubectl_out[*]}" -- "$cur" ) )
fi fi
} }
...@@ -196,6 +231,14 @@ Find more information at https://github.com/kubernetes/kubernetes.`, ...@@ -196,6 +231,14 @@ Find more information at https://github.com/kubernetes/kubernetes.`,
cmds.AddCommand(NewCmdExplain(f, out)) cmds.AddCommand(NewCmdExplain(f, out))
cmds.AddCommand(NewCmdConvert(f, out)) cmds.AddCommand(NewCmdConvert(f, out))
if cmds.Flag("namespace").Annotations == nil {
cmds.Flag("namespace").Annotations = map[string][]string{}
}
cmds.Flag("namespace").Annotations[cobra.BashCompCustom] = append(
cmds.Flag("namespace").Annotations[cobra.BashCompCustom],
"__kubectl_get_namespaces",
)
return cmds return cmds
} }
......
...@@ -71,11 +71,12 @@ func NewCmdDelete(f *cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -71,11 +71,12 @@ func NewCmdDelete(f *cmdutil.Factory, out io.Writer) *cobra.Command {
options := &DeleteOptions{} options := &DeleteOptions{}
// retrieve a list of handled resources from printer as valid args // retrieve a list of handled resources from printer as valid args
validArgs := []string{} validArgs, argAliases := []string{}, []string{}
p, err := f.Printer(nil, false, false, false, false, false, false, []string{}) p, err := f.Printer(nil, false, false, false, false, false, false, []string{})
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
if p != nil { if p != nil {
validArgs = p.HandledResources() validArgs = p.HandledResources()
argAliases = kubectl.ResourceAliases(validArgs)
} }
cmd := &cobra.Command{ cmd := &cobra.Command{
...@@ -88,7 +89,8 @@ func NewCmdDelete(f *cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -88,7 +89,8 @@ func NewCmdDelete(f *cmdutil.Factory, out io.Writer) *cobra.Command {
err := RunDelete(f, out, cmd, args, options) err := RunDelete(f, out, cmd, args, options)
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
}, },
ValidArgs: validArgs, ValidArgs: validArgs,
ArgAliases: argAliases,
} }
usage := "Filename, directory, or URL to a file containing the resource to delete." usage := "Filename, directory, or URL to a file containing the resource to delete."
kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage) kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
......
...@@ -74,6 +74,9 @@ kubectl describe pods frontend` ...@@ -74,6 +74,9 @@ kubectl describe pods frontend`
func NewCmdDescribe(f *cmdutil.Factory, out io.Writer) *cobra.Command { func NewCmdDescribe(f *cmdutil.Factory, out io.Writer) *cobra.Command {
options := &DescribeOptions{} options := &DescribeOptions{}
validArgs := kubectl.DescribableResources()
argAliases := kubectl.ResourceAliases(validArgs)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)", Use: "describe (-f FILENAME | TYPE [NAME_PREFIX | -l label] | TYPE/NAME)",
Short: "Show details of a specific resource or group of resources", Short: "Show details of a specific resource or group of resources",
...@@ -83,7 +86,8 @@ func NewCmdDescribe(f *cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -83,7 +86,8 @@ func NewCmdDescribe(f *cmdutil.Factory, out io.Writer) *cobra.Command {
err := RunDescribe(f, out, cmd, args, options) err := RunDescribe(f, out, cmd, args, options)
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
}, },
ValidArgs: kubectl.DescribableResources(), ValidArgs: validArgs,
ArgAliases: argAliases,
} }
usage := "Filename, directory, or URL to a file containing the resource to describe" usage := "Filename, directory, or URL to a file containing the resource to describe"
kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage) kubectl.AddJsonFilenameFlag(cmd, &options.Filenames, usage)
......
...@@ -74,11 +74,12 @@ func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -74,11 +74,12 @@ func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command {
options := &GetOptions{} options := &GetOptions{}
// retrieve a list of handled resources from printer as valid args // retrieve a list of handled resources from printer as valid args
validArgs := []string{} validArgs, argAliases := []string{}, []string{}
p, err := f.Printer(nil, false, false, false, false, false, false, []string{}) p, err := f.Printer(nil, false, false, false, false, false, false, []string{})
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
if p != nil { if p != nil {
validArgs = p.HandledResources() validArgs = p.HandledResources()
argAliases = kubectl.ResourceAliases(validArgs)
} }
cmd := &cobra.Command{ cmd := &cobra.Command{
...@@ -90,7 +91,8 @@ func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -90,7 +91,8 @@ func NewCmdGet(f *cmdutil.Factory, out io.Writer) *cobra.Command {
err := RunGet(f, out, cmd, args, options) err := RunGet(f, out, cmd, args, options)
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
}, },
ValidArgs: validArgs, ValidArgs: validArgs,
ArgAliases: argAliases,
} }
cmdutil.AddPrinterFlags(cmd) cmdutil.AddPrinterFlags(cmd)
cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on") cmd.Flags().StringP("selector", "l", "", "Selector (label query) to filter on")
......
...@@ -73,11 +73,12 @@ func NewCmdLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -73,11 +73,12 @@ func NewCmdLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command {
options := &LabelOptions{} options := &LabelOptions{}
// retrieve a list of handled resources from printer as valid args // retrieve a list of handled resources from printer as valid args
validArgs := []string{} validArgs, argAliases := []string{}, []string{}
p, err := f.Printer(nil, false, false, false, false, false, false, []string{}) p, err := f.Printer(nil, false, false, false, false, false, false, []string{})
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
if p != nil { if p != nil {
validArgs = p.HandledResources() validArgs = p.HandledResources()
argAliases = kubectl.ResourceAliases(validArgs)
} }
cmd := &cobra.Command{ cmd := &cobra.Command{
...@@ -89,7 +90,8 @@ func NewCmdLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command { ...@@ -89,7 +90,8 @@ func NewCmdLabel(f *cmdutil.Factory, out io.Writer) *cobra.Command {
err := RunLabel(f, out, cmd, args, options) err := RunLabel(f, out, cmd, args, options)
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
}, },
ValidArgs: validArgs, ValidArgs: validArgs,
ArgAliases: argAliases,
} }
cmdutil.AddPrinterFlags(cmd) cmdutil.AddPrinterFlags(cmd)
cmd.Flags().Bool("overwrite", false, "If true, allow labels to be overwritten, otherwise reject label updates that overwrite existing labels.") cmd.Flags().Bool("overwrite", false, "If true, allow labels to be overwritten, otherwise reject label updates that overwrite existing labels.")
......
...@@ -175,6 +175,35 @@ func expandResourceShortcut(resource unversioned.GroupVersionResource) unversion ...@@ -175,6 +175,35 @@ func expandResourceShortcut(resource unversioned.GroupVersionResource) unversion
return resource return resource
} }
// ResourceAliases returns the resource shortcuts and plural forms for the given resources.
func ResourceAliases(rs []string) []string {
as := make([]string, 0, len(rs))
plurals := make(map[string]struct{}, len(rs))
for _, r := range rs {
var plural string
switch {
case r == "endpoints":
plural = r // exception. "endpoint" does not exist. Why?
case strings.HasSuffix(r, "y"):
plural = r[0:len(r)-1] + "ies"
case strings.HasSuffix(r, "s"):
plural = r + "es"
default:
plural = r + "s"
}
as = append(as, plural)
plurals[plural] = struct{}{}
}
for sf, r := range shortForms {
if _, found := plurals[r]; found {
as = append(as, sf)
}
}
return as
}
// parseFileSource parses the source given. Acceptable formats include: // parseFileSource parses the source given. Acceptable formats include:
// //
// 1. source-path: the basename will become the key name // 1. source-path: the basename will become the key name
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment