From e9d528db5800d69cb3565dbabe0331bcc0c103af Mon Sep 17 00:00:00 2001 From: Aleksey Maksimov Date: Fri, 13 Sep 2019 11:39:57 +0800 Subject: [PATCH] added kubens/kubectx and various small changes --- .vimrc | 22 ++-- .zshrc | 5 +- completions/_kubectx.zsh | 12 ++ completions/_kubens.zsh | 2 + local/bin/kubectx | 233 +++++++++++++++++++++++++++++++++++++++ local/bin/kubens | 219 ++++++++++++++++++++++++++++++++++++ 6 files changed, 481 insertions(+), 12 deletions(-) create mode 100644 completions/_kubectx.zsh create mode 100644 completions/_kubens.zsh create mode 100755 local/bin/kubectx create mode 100755 local/bin/kubens diff --git a/.vimrc b/.vimrc index b35197d..4389281 100644 --- a/.vimrc +++ b/.vimrc @@ -28,15 +28,6 @@ Plugin 'dkprice/vim-easygrep' " Grep plugin Plugin 'scrooloose/nerdtree' " Filesystem manipulation -" Plugin 'talek/obvious-resize' -" Resize split windows with Ctrl+move keys - doesn't work -" Plugin 'ervandew/supertab' -" Dropdown suggestions on TAB key press -" Plugin 'vim-scripts/mru.vim' -" Most recently used files -" Plugin 'basepi/vim-conque' -" Shell within VIM buffer -" Plugin 'kien/ctrlp.vim' Plugin 'ctrlpvim/ctrlp.vim' " Find files on Ctrl+P press "Plugin 'Lokaltog/vim-powerline.git' @@ -239,6 +230,9 @@ autocmd BufWritePre *.html call TrimWhiteSpace() autocmd BufWritePre *.groovy call TrimWhiteSpace() "autocmd BufWritePost *.py call Flake8() +autocmd FileType groovy let b:dispatch = '/home/sabuser/src/scom-pipeline-library/cd/lint.sh' +au BufRead *.groovy try | execute "compiler groovy" | catch /./| endtry + " CtrlP settings set wildignore+=*.sw*,*.pyc,*.class @@ -308,7 +302,7 @@ autocmd FileType go nmap gi (go-install) " Fugitive -nnoremap gg :Gstatus +nnoremap gg :15Gstatus nnoremap ga :Gwrite nnoremap gc :Gcommit % nnoremap gd :Gdiff @@ -426,7 +420,7 @@ function! LightLineFugitive() try if expand('%:t') !~? 'Tagbar\|Gundo\|NERD' && &ft !~? 'vimfiler' && exists('*fugitive#head') let mark = '' " edit here for cool mark - let branch = fugitive#head() + let branch = fugitive#head(8) return branch !=# '' ? mark.branch : '' endif catch @@ -607,4 +601,10 @@ let g:syntastic_check_on_open = 0 let g:syntastic_check_on_wq = 0 let g:syntastic_python_checkers = ['pep8','pyflakes'] let g:syntastic_aggregate_errors = 1 +<<<<<<< HEAD >>>>>>> upgrade vundle and plugins +======= + +let g:startify_change_to_vcs_root = 1 +let g:startify_change_to_dir = 0 +>>>>>>> added kubens/kubectx and various small changes diff --git a/.zshrc b/.zshrc index f00cbf3..9c639d2 100644 --- a/.zshrc +++ b/.zshrc @@ -55,7 +55,6 @@ plugins=(git python pip docker vi-mode kubectl tmux) source $ZSH/oh-my-zsh.sh alias ls-al='nocorrect ls -al' -alias grep='grep -n -I' alias rsync='noglob rsync' alias docker='sudo docker $@' alias proxy='export http_proxy=http://10.65.128.43:8080;export https_proxy=http://10.65.128.43:8080' @@ -98,6 +97,7 @@ bindkey '^w' backward-kill-word # ctrl-r starts searching history backward bindkey '^r' history-incremental-search-backward +export ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="bg=bold,underline" function source_config() { if [ -r $PWD/.zsh_config ]; then print "Sourcing $PWD/.zsh_config" @@ -168,3 +168,6 @@ export GPG_AGENT_INFO # added by travis gem [ -f /home/aleksey/.travis/travis.sh ] && source /home/aleksey/.travis/travis.sh (cat ~/.cache/wal/sequences &) +eval "$(direnv hook zsh)" + +[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh diff --git a/completions/_kubectx.zsh b/completions/_kubectx.zsh new file mode 100644 index 0000000..275f71a --- /dev/null +++ b/completions/_kubectx.zsh @@ -0,0 +1,12 @@ +#compdef kubectx kctx=kubectx + +local KUBECTX="${HOME}/.kube/kubectx" +PREV="" +if [ -f "$KUBECTX" ]; then + # show '-' only if there's a saved previous context + local PREV=$(cat "${KUBECTX}") + _arguments "1: :(- + $(kubectl config get-contexts --output='name'))" +else + _arguments "1: :($(kubectl config get-contexts --output='name'))" +fi diff --git a/completions/_kubens.zsh b/completions/_kubens.zsh new file mode 100644 index 0000000..e523caf --- /dev/null +++ b/completions/_kubens.zsh @@ -0,0 +1,2 @@ +#compdef kubens kns=kubens +_arguments "1: :(- $(kubectl get namespaces -o=jsonpath='{range .items[*].metadata.name}{@}{"\n"}{end}'))" diff --git a/local/bin/kubectx b/local/bin/kubectx new file mode 100755 index 0000000..b168a9c --- /dev/null +++ b/local/bin/kubectx @@ -0,0 +1,233 @@ +#!/usr/bin/env bash +# +# kubectx(1) is a utility to manage and switch between kubectl contexts. + +# Copyright 2017 Google Inc. +# +# 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. + +[[ -n $DEBUG ]] && set -x + +set -eou pipefail +IFS=$'\n\t' + +SELF_CMD="$0" +KUBECTX="${XDG_CACHE_HOME:-$HOME/.kube}/kubectx" + +usage() { + cat <<"EOF" +USAGE: + kubectx : list the contexts + kubectx : switch to context + kubectx - : switch to the previous context + kubectx -c, --current : show the current context name + kubectx = : rename context to + kubectx =. : rename current-context to + kubectx -d [] : delete context ('.' for current-context) + (this command won't delete the user/cluster entry + that is used by the context) + + kubectx -h,--help : show this message +EOF +} + +exit_err() { + echo >&2 "${1}" + exit 1 +} + +current_context() { + $KUBECTL config view -o=jsonpath='{.current-context}' +} + +get_contexts() { + $KUBECTL config get-contexts -o=name | sort -n +} + +list_contexts() { + set -u pipefail + local cur ctx_list + cur="$(current_context)" || exit_err "error getting current context" + ctx_list=$(get_contexts) || exit_err "error getting context list" + + local yellow darkbg normal + yellow=$(tput setaf 3 || true) + darkbg=$(tput setab 0 || true) + normal=$(tput sgr0 || true) + + local cur_ctx_fg cur_ctx_bg + cur_ctx_fg=${KUBECTX_CURRENT_FGCOLOR:-$yellow} + cur_ctx_bg=${KUBECTX_CURRENT_BGCOLOR:-$darkbg} + + for c in $ctx_list; do + if [[ -n "${_KUBECTX_FORCE_COLOR:-}" || \ + -t 1 && -z "${NO_COLOR:-}" ]]; then + # colored output mode + if [[ "${c}" = "${cur}" ]]; then + echo "${cur_ctx_bg}${cur_ctx_fg}${c}${normal}" + else + echo "${c}" + fi + else + echo "${c}" + fi + done +} + +read_context() { + if [[ -f "${KUBECTX}" ]]; then + cat "${KUBECTX}" + fi +} + +save_context() { + local saved + saved="$(read_context)" + + if [[ "${saved}" != "${1}" ]]; then + printf %s "${1}" > "${KUBECTX}" + fi +} + +switch_context() { + $KUBECTL config use-context "${1}" +} + +choose_context_interactive() { + local choice + choice="$(_KUBECTX_FORCE_COLOR=1 \ + FZF_DEFAULT_COMMAND="${SELF_CMD}" \ + fzf --ansi || true)" + if [[ -z "${choice}" ]]; then + echo 2>&1 "error: you did not choose any of the options" + exit 1 + else + set_context "${choice}" + fi +} + +set_context() { + local prev + prev="$(current_context)" || exit_err "error getting current context" + + switch_context "${1}" + + if [[ "${prev}" != "${1}" ]]; then + save_context "${prev}" + fi +} + +swap_context() { + local ctx + ctx="$(read_context)" + if [[ -z "${ctx}" ]]; then + echo "error: No previous context found." >&2 + exit 1 + fi + set_context "${ctx}" +} + +context_exists() { + grep -q ^"${1}"\$ <($KUBECTL config get-contexts -o=name) +} + +rename_context() { + local old_name="${1}" + local new_name="${2}" + + if [[ "${old_name}" == "." ]]; then + old_name="$(current_context)" + fi + + if ! context_exists "${old_name}"; then + echo "error: Context \"${old_name}\" not found, can't rename it." >&2 + exit 1 + fi + + if context_exists "${new_name}"; then + echo "Context \"${new_name}\" exists, deleting..." >&2 + $KUBECTL config delete-context "${new_name}" 1>/dev/null 2>&1 + fi + + $KUBECTL config rename-context "${old_name}" "${new_name}" +} + +delete_contexts() { + for i in "${@}"; do + delete_context "${i}" + done +} + +delete_context() { + local ctx + ctx="${1}" + if [[ "${ctx}" == "." ]]; then + ctx="$(current_context)" || exit_err "error getting current context" + fi + echo "Deleting context \"${ctx}\"..." >&2 + $KUBECTL config delete-context "${ctx}" +} + +main() { + if hash kubectl 2>/dev/null; then + KUBECTL=kubectl + elif hash kubectl.exe 2>/dev/null; then + KUBECTL=kubectl.exe + else + echo >&2 "kubectl is not installed" + exit 1 + fi + + if [[ "$#" -eq 0 ]]; then + if [[ -t 1 && -z "${KUBECTX_IGNORE_FZF:-}" && "$(type fzf &>/dev/null; echo $?)" -eq 0 ]]; then + choose_context_interactive + else + list_contexts + fi + elif [[ "${1}" == "-d" ]]; then + if [[ "$#" -lt 2 ]]; then + echo "error: missing context NAME" >&2 + usage + exit 1 + fi + delete_contexts "${@:2}" + elif [[ "$#" -gt 1 ]]; then + echo "error: too many arguments" >&2 + usage + exit 1 + elif [[ "$#" -eq 1 ]]; then + if [[ "${1}" == "-" ]]; then + swap_context + elif [[ "${1}" == '-c' || "${1}" == '--current' ]]; then + # we don't call current_context here for two reasons: + # - it does not fail when current-context property is not set + # - it does not return a trailing newline + kubectl config current-context + elif [[ "${1}" == '-h' || "${1}" == '--help' ]]; then + usage + elif [[ "${1}" =~ ^-(.*) ]]; then + echo "error: unrecognized flag \"${1}\"" >&2 + usage + exit 1 + elif [[ "${1}" =~ (.+)=(.+) ]]; then + rename_context "${BASH_REMATCH[2]}" "${BASH_REMATCH[1]}" + else + set_context "${1}" + fi + else + usage + exit 1 + fi +} + +main "$@" diff --git a/local/bin/kubens b/local/bin/kubens new file mode 100755 index 0000000..c010122 --- /dev/null +++ b/local/bin/kubens @@ -0,0 +1,219 @@ +#!/usr/bin/env bash +# +# kubens(1) is a utility to switch between Kubernetes namespaces. + +# Copyright 2017 Google Inc. +# +# 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. + +[[ -n $DEBUG ]] && set -x + +set -eou pipefail +IFS=$'\n\t' + +SELF_CMD="$0" +KUBENS_DIR="${XDG_CACHE_HOME:-$HOME/.kube}/kubens" + +usage() { + cat <<"EOF" +USAGE: + kubens : list the namespaces in the current context + kubens : change the active namespace of current context + kubens - : switch to the previous namespace in this context + kubens -c, --current : show the current namespace + kubens -h,--help : show this message +EOF +} + +exit_err() { + echo >&2 "${1}" + exit 1 +} + +current_namespace() { + local cur_ctx + + cur_ctx="$(current_context)" || exit_err "error getting current context" + ns="$($KUBECTL config view -o=jsonpath="{.contexts[?(@.name==\"${cur_ctx}\")].context.namespace}")" \ + || exit_err "error getting current namespace" + + if [[ -z "${ns}" ]]; then + echo "default" + else + echo "${ns}" + fi +} + +current_context() { + $KUBECTL config current-context +} + +get_namespaces() { + $KUBECTL get namespaces -o=jsonpath='{range .items[*].metadata.name}{@}{"\n"}{end}' +} + +escape_context_name() { + echo "${1//\//-}" +} + +namespace_file() { + local ctx + + ctx="$(escape_context_name "${1}")" + echo "${KUBENS_DIR}/${ctx}" +} + +read_namespace() { + local f + f="$(namespace_file "${1}")" + [[ -f "${f}" ]] && cat "${f}" + return 0 +} + +save_namespace() { + mkdir -p "${KUBENS_DIR}" + local f saved + f="$(namespace_file "${1}")" + saved="$(read_namespace "${1}")" + + if [[ "${saved}" != "${2}" ]]; then + printf %s "${2}" > "${f}" + fi +} + +switch_namespace() { + local ctx="${1}" + $KUBECTL config set-context "${ctx}" --namespace="${2}" + echo "Active namespace is \"${2}\".">&2 +} + +choose_namespace_interactive() { + # directly calling kubens via fzf might fail with a cryptic error like + # "$FZF_DEFAULT_COMMAND failed", so try to see if we can list namespaces + # locally first + if [[ -z "$(list_namespaces)" ]]; then + echo >&2 "error: could not list namespaces (is the cluster accessible?)" + exit 1 + fi + + local choice + choice="$(_KUBECTX_FORCE_COLOR=1 \ + FZF_DEFAULT_COMMAND="${SELF_CMD}" \ + fzf --ansi || true)" + if [[ -z "${choice}" ]]; then + echo 2>&1 "error: you did not choose any of the options" + exit 1 + else + set_namespace "${choice}" + fi +} + +set_namespace() { + local ctx prev + ctx="$(current_context)" || exit_err "error getting current context" + prev="$(current_namespace)" || exit_error "error getting current namespace" + + if grep -q ^"${1}"\$ <(get_namespaces); then + switch_namespace "${ctx}" "${1}" + + if [[ "${prev}" != "${1}" ]]; then + save_namespace "${ctx}" "${prev}" + fi + else + echo "error: no namespace exists with name \"${1}\".">&2 + exit 1 + fi +} + +list_namespaces() { + local yellow darkbg normal + yellow=$(tput setaf 3 || true) + darkbg=$(tput setab 0 || true) + normal=$(tput sgr0 || true) + + local cur_ctx_fg cur_ctx_bg + cur_ctx_fg=${KUBECTX_CURRENT_FGCOLOR:-$yellow} + cur_ctx_bg=${KUBECTX_CURRENT_BGCOLOR:-$darkbg} + + local cur ns_list + cur="$(current_namespace)" || exit_err "error getting current namespace" + ns_list=$(get_namespaces) || exit_err "error getting namespace list" + + for c in $ns_list; do + if [[ -n "${_KUBECTX_FORCE_COLOR:-}" || \ + -t 1 && -z "${NO_COLOR:-}" ]]; then + # colored output mode + if [[ "${c}" = "${cur}" ]]; then + echo "${cur_ctx_bg}${cur_ctx_fg}${c}${normal}" + else + echo "${c}" + fi + else + echo "${c}" + fi + done +} + +swap_namespace() { + local ctx ns + ctx="$(current_context)" || exit_err "error getting current context" + ns="$(read_namespace "${ctx}")" + if [[ -z "${ns}" ]]; then + echo "error: No previous namespace found for current context." >&2 + exit 1 + fi + set_namespace "${ns}" +} + +main() { + if [[ -z "${KUBECTL:-}" ]]; then + if hash kubectl 2>/dev/null; then + KUBECTL=kubectl + elif hash kubectl.exe 2>/dev/null; then + KUBECTL=kubectl.exe + else + echo >&2 "kubectl is not installed" + exit 1 + fi + fi + + if [[ "$#" -eq 0 ]]; then + if [[ -t 1 && -z ${KUBECTX_IGNORE_FZF:-} && "$(type fzf &>/dev/null; echo $?)" -eq 0 ]]; then + choose_namespace_interactive + else + list_namespaces + fi + elif [[ "$#" -eq 1 ]]; then + if [[ "${1}" == '-h' || "${1}" == '--help' ]]; then + usage + elif [[ "${1}" == "-" ]]; then + swap_namespace + elif [[ "${1}" == '-c' || "${1}" == '--current' ]]; then + current_namespace + elif [[ "${1}" =~ ^-(.*) ]]; then + echo "error: unrecognized flag \"${1}\"" >&2 + usage + exit 1 + elif [[ "${1}" =~ (.+)=(.+) ]]; then + alias_context "${BASH_REMATCH[2]}" "${BASH_REMATCH[1]}" + else + set_namespace "${1}" + fi + else + echo "error: too many flags" >&2 + usage + exit 1 + fi +} + +main "$@"