Last active
October 2, 2025 08:53
-
-
Save pvdb/813b5ba5bb1383c526d9dbcde64c9878 to your computer and use it in GitHub Desktop.
kubectl wrapper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# | |
# WHAT | |
# | |
# kubektl - interactive kubectl wrapper | |
# | |
# Dixit "Claude Snonnet 4" -- This is a well-designed utility that significantly improves the developer experience | |
# when working with Kubernetes clusters, especially in environments with many contexts, namespaces, and resources! | |
# | |
# INSTALLATION | |
# | |
# ln -s ${PWD}/kubektl $(brew --prefix)/bin/ | |
# sudo ln -s ${PWD}/kubektl /usr/local/bin/ | |
# | |
# PREREQUISITES | |
# | |
# brew install fzf | |
# brew install lolcat | |
# | |
# define the cache directory | |
export cache_home=${XDG_CACHE_HOME:-$HOME/.cache}/kubektl ; | |
# view the cache directory | |
# lsd --tree ${XDG_CACHE_HOME:-$HOME/.cache}/kubektl/ ; | |
# clear the cache directory | |
# rm -rf ${XDG_CACHE_HOME:-$HOME/.cache}/kubektl/* ; | |
# by default do not refresh the cache | |
refresh_cache=false ; | |
# detect the optional --refresh clarg | |
if [[ "$1" = "--refresh" ]] ; then | |
# set the refresh_cache flag | |
refresh_cache=true ; | |
# remove --refresh from arguments | |
shift ; | |
fi | |
set -e ; # CTRL-C or ESC (empty selection) in fzf will exit the script | |
select_from_list() { | |
label=$(echo "Select a ${1:-item} ..."|lolcat -f) ; | |
fzf --height="~100%" --border --border-label-pos=5:top --border-label="> ${label} <" ; | |
} | |
select_from_list_or_exit() { | |
selected_item=$(select_from_list "${1:-item}") ; | |
if [[ -z "${selected_item}" ]] ; then | |
> /dev/tty echo "No ${1:-item} selected, aborting!" ; | |
/usr/bin/env false ; | |
else | |
highlighted_item=$(echo "\"${selected_item}\"" | lolcat -f) ; | |
> /dev/tty printf "Selected ${1:-item}: %s\n" "${highlighted_item}" ; | |
echo "${selected_item}" ; | |
fi | |
} | |
export kube_context=""; | |
export kube_namespace=""; | |
export kube_pod=""; | |
export pod_container=""; | |
context() { | |
[[ -z "${kube_context}" ]] && kube_context=$( | |
cache_dir="${cache_home}" ; | |
cache_file="${cache_dir}/kube_contexts.txt" ; | |
[[ "${refresh_cache}" == "true" ]] && rm -f "${cache_file}" ; | |
[[ -f "${cache_file}" ]] || ( | |
mkdir -p "${cache_dir}" ; | |
command kubectl config view | \ | |
yq '.contexts[].name' \ | |
> "${cache_file}" ; | |
) ; | |
< "${cache_file}" select_from_list_or_exit 'kube context' ; | |
) ; | |
echo "${kube_context}" ; | |
} | |
namespace() { | |
> /dev/null context ; # prime the kube context | |
[[ -z "${kube_namespace}" ]] && kube_namespace=$( | |
cache_dir="${cache_home}/${kube_context}" ; | |
cache_file="${cache_dir}/kube_namespaces.txt" ; | |
[[ "${refresh_cache}" == "true" ]] && rm -f "${cache_file}" ; | |
[[ -f "${cache_file}" ]] || ( | |
mkdir -p "${cache_dir}" ; | |
command kubectl --output=json --context "$(context)" get namespaces | \ | |
jq -r '.items[].metadata.name' \ | |
> "${cache_file}" ; | |
# jq -r '.items[] | select(.status.phase=="Active") | .metadata.name' | |
) ; | |
< "${cache_file}" select_from_list_or_exit 'kube namespace' ; | |
) ; | |
echo "${kube_namespace}" ; | |
} | |
pod() { | |
> /dev/null namespace ; # prime the kube namespace (and context) | |
[[ -z "${kube_pod}" ]] && kube_pod=$( | |
cache_dir="${cache_home}/${kube_context}/${kube_namespace}" ; | |
cache_file="${cache_dir}/kube_pods.txt" ; | |
[[ "${refresh_cache}" == "true" ]] && rm -f "${cache_file}" ; | |
[[ -f "${cache_file}" ]] || ( | |
mkdir -p "${cache_dir}" ; | |
command kubectl --output=json --context "$(context)" --namespace "$(namespace)" get pods | \ | |
jq -r '.items[]|.metadata.name' \ | |
> "${cache_file}" ; | |
# jq -r '.items[] | select(.status.phase=="Running") | .metadata.name' | |
) | |
< "${cache_file}" select_from_list_or_exit 'kube pod' ; | |
) ; | |
echo "${kube_pod}" ; | |
} | |
container() { | |
> /dev/null pod ; # prime the kube pod (and namespace, and context) | |
[[ -z "${pod_container}" ]] && pod_container=$( | |
cache_dir="${cache_home}/${kube_context}/${kube_namespace}/${kube_pod}" ; | |
cache_file="${cache_dir}/pod_containers.txt" ; | |
[[ "${refresh_cache}" == "true" ]] && rm -f "${cache_file}" ; | |
[[ -f "${cache_file}" ]] || ( | |
mkdir -p "${cache_dir}" ; | |
command kubectl --output=json --context "$(context)" --namespace "$(namespace)" get pods "$(pod)" | \ | |
jq -r '.spec.containers[].name' \ | |
> "${cache_file}" ; | |
) | |
< "${cache_file}" select_from_list_or_exit 'pod container' ; | |
) ; | |
echo "${pod_container}" ; | |
} | |
kubectl_cmd="$1" ; shift ; | |
case "${kubectl_cmd}" in | |
"exec") | |
> /dev/null container ; # prime the pod container | |
[[ $# -eq 0 ]] && ( | |
command kubectl --context "$(context)" exec -it --namespace "$(namespace)" "$(pod)" --container "$(container)" -- /bin/sh ; | |
) | |
[[ $# -ne 0 ]] && ( | |
command kubectl --context "$(context)" exec -it --namespace "$(namespace)" "$(pod)" --container "$(container)" -- /bin/sh -c "$*" ; | |
) | |
;; | |
"logs") | |
> /dev/null container ; # prime the pod container | |
command kubectl --context "$(context)" logs "$@" --namespace "$(namespace)" "$(pod)" --container "$(container)" ; | |
;; | |
"pods") | |
> /dev/null namespace ; # prime the kube namespace | |
command kubectl --context "$(context)" get pods -o wide --namespace "$(namespace)" ; | |
;; | |
"port-forward") | |
> /dev/null pod ; # prime the kube pod | |
command kubectl --context "$(context)" --namespace "$(namespace)" port-forward pod/"$(pod)" "$@" ; | |
;; | |
"delete") | |
> /dev/null pod ; # prime the kube pod | |
command kubectl --context "$(context)" delete pod --namespace "$(namespace)" "$(pod)" --now --interactive ; | |
;; | |
*) | |
> /dev/null context ; # prime the kube context | |
command kubectl --context "$(context)" "$@" ; | |
;; | |
esac | |
# That's all Folks! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment