From f6878aed3c8019c15d514dc5549e0e09225e40aa Mon Sep 17 00:00:00 2001 From: Eric Paris Date: Tue, 17 Mar 2015 13:00:48 -0400 Subject: [PATCH] Add bash completion custom functions These functions call out to kubectl to get information about running resources. They give us completions which are kubernetes aware and thus obviously better than just cobra subcommands and flags. --- contrib/completions/bash/kubectl | 67 ++++++++++++++++++++++++++++++ pkg/kubectl/cmd/cmd.go | 71 ++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) diff --git a/contrib/completions/bash/kubectl b/contrib/completions/bash/kubectl index 201d9acea2d..c4cd4e0812d 100644 --- a/contrib/completions/bash/kubectl +++ b/contrib/completions/bash/kubectl @@ -149,6 +149,73 @@ __handle_word() __handle_word } +# call kubectl get $1, +# use the first column in compgen +# we could use templates, but then would need a template per resource +__kubectl_parse_get() +{ + local kubectl_output out + if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then + out=($(echo "${kubectl_output}" | awk '{print $1}')) + COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) + fi +} + +__kubectl_get_resource() +{ + if [[ ${#nouns[@]} -eq 0 ]]; then + return 1 + fi + __kubectl_parse_get ${nouns[${#nouns[@]} -1]} + if [[ $? -eq 0 ]]; then + return 0 + fi +} + +# $1 is the name of the pod we want to get the list of containers inside +__kubectl_get_containers() +{ + local template + template="{{ range .desiredState.manifest.containers }}{{ .name }} {{ end }}" + __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 get -o template --template="${template}" pods "${last}" 2>/dev/null); 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 +} + +__custom_func() { + case ${last_command} in + kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop) + __kubectl_get_resource + return + ;; + kubectl_log) + __kubectl_require_pod_and_container + return + ;; + *) + ;; + esac +} + _kubectl_get() { last_command="kubectl_get" diff --git a/pkg/kubectl/cmd/cmd.go b/pkg/kubectl/cmd/cmd.go index 736a5dbcbfd..bf835c653f7 100644 --- a/pkg/kubectl/cmd/cmd.go +++ b/pkg/kubectl/cmd/cmd.go @@ -26,6 +26,76 @@ import ( "github.com/spf13/cobra" ) +const ( + bash_completion_func = `# call kubectl get $1, +# use the first column in compgen +# we could use templates, but then would need a template per resource +__kubectl_parse_get() +{ + local kubectl_output out + if kubectl_output=$(kubectl get --no-headers "$1" 2>/dev/null); then + out=($(echo "${kubectl_output}" | awk '{print $1}')) + COMPREPLY=( $( compgen -W "${out[*]}" -- "$cur" ) ) + fi +} + +__kubectl_get_resource() +{ + if [[ ${#nouns[@]} -eq 0 ]]; then + return 1 + fi + __kubectl_parse_get ${nouns[${#nouns[@]} -1]} + if [[ $? -eq 0 ]]; then + return 0 + fi +} + +# $1 is the name of the pod we want to get the list of containers inside +__kubectl_get_containers() +{ + local template + template="{{ range .desiredState.manifest.containers }}{{ .name }} {{ end }}" + __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 get -o template --template="${template}" pods "${last}" 2>/dev/null); 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 +} + +__custom_func() { + case ${last_command} in + kubectl_get | kubectl_describe | kubectl_delete | kubectl_stop) + __kubectl_get_resource + return + ;; + kubectl_log) + __kubectl_require_pod_and_container + return + ;; + *) + ;; + esac +} +` +) + // NewKubectlCommand creates the `kubectl` command and its nested children. func NewKubectlCommand(f *cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command { // Parent command to which all subcommands are added. @@ -36,6 +106,7 @@ func NewKubectlCommand(f *cmdutil.Factory, in io.Reader, out, err io.Writer) *co Find more information at https://github.com/GoogleCloudPlatform/kubernetes.`, Run: runHelp, + BashCompletionFunction: bash_completion_func, } f.BindFlags(cmds.PersistentFlags())