Last active
August 23, 2023 02:03
-
-
Save augustohp/deebc619c515463b9df6f46d8c7376af to your computer and use it in GitHub Desktop.
Execute a shell inside a running pod in kubernetes, uses fuzze search to traverse among available namespaces and pods.
This file contains 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 sh | |
# | |
# Allows you to execute a shell into a running pod inside k8s. You can | |
# execute this script/command without any argument and it will display | |
# all available namespaces, then all available pods in the chosen namespace | |
# and then enter the pod you chose. | |
# | |
# Choices are given using fzf, allowing you to fuzzy search among occurrences. | |
# | |
# # Author: Augusto Pascutti <augusto.hp+oss@gmail> | |
# License: MIT | |
# URL: https://gist.github.com/augustohp/deebc619c515463b9df6f46d8c7376af | |
# FZF: https://github.com/junegunn/fzf | |
# vim: set ft=sh ts=4 sw=4 tw=0 noet: | |
# shellcheck disable=SC3043 | |
APP_NAME=$(basename "$0") | |
APP_VERSION="1.0.0" | |
APP_AUTHOR="augusto.hp+oss@gmail.com" | |
APP_DEPENDENCIES="kubectl awk fzf" | |
OPTION_NAMESPACE="" | |
OPTION_POD="" | |
OPTION_SHELL="/bin/sh" | |
set -e # Stops on failure | |
trap cleanup INT TERM EXIT | |
# Usage: cleanup | |
cleanup() | |
{ | |
exit 1 | |
} | |
# Usage: assert_env | |
assert_env() | |
{ | |
for dependency in $APP_DEPENDENCIES | |
do | |
if [ -n "$(command -v "$dependency")" ] | |
then | |
continue | |
fi | |
err "Missing dependency '$dependency', please install it." | |
exit 2 | |
done | |
} | |
# Usage: if empty "" && echo "empty" | |
empty() | |
{ | |
local value="$1" | |
if [ -z "$value" ] | |
then | |
return 0 | |
fi | |
return 1 | |
} | |
# Usage: kubectl get ns | strip_k8s_header | |
strip_k8s_header() | |
{ | |
grep -v "NAME" | |
} | |
# Usage: kubectl get ns | only_column 1 | |
only_column() | |
{ | |
local column="$1" | |
awk "{ print \$${column} }" | |
} | |
# ----------------------------------------------------------------------------- | |
# Context | |
# Filters the input with fuzzy search, the output is the line selected. | |
# Usage: cat /etc/hosts | fzf_menu [prompt] | |
fzf_menu() | |
{ | |
local header="Choose an option below (with arrow keys and ENTER):" | |
fzf --header="$header" \ | |
--height=35% \ | |
--reverse | |
} | |
# Usage: namespace="$(choose_namespace)" | |
choose_namespace() | |
{ | |
kubectl get namespaces \ | |
| strip_k8s_header \ | |
| only_column 1 \ | |
| fzf_menu "Choose a namespace" | |
} | |
# Usage: pod="$(choose_pod <namespace>)" | |
choose_pod() | |
{ | |
local namespace="$1" | |
kubectl get pods --namespace "$namespace" \ | |
| strip_k8s_header \ | |
| only_column 1 \ | |
| fzf_menu "Choose pod" | |
} | |
# Usage: enter_shell <pod> <shell> | |
enter_shell() | |
{ | |
local pod="$1" | |
local shell="$2" | |
kubectl exec --stdin --tty "$pod" -- "$shell" | |
} | |
# Usage: pod_state <pod> | |
pod_state() | |
{ | |
local pod="$1" | |
kubectl get pod "$pod" \ | |
| strip_k8s_header \ | |
| only_column 3 | |
} | |
# Usage: if pod_not_running <pod> && echo "NOT running" | |
pod_not_running() | |
{ | |
local pod="$1" | |
state="$(pod_state "$pod")" | |
if [ "$state" = "Running" ] | |
then | |
return 1 | |
fi | |
return 0 | |
} | |
# ----------------------------------------------------------------------------- | |
# Execution | |
# Usage: display_help | |
display_help() | |
{ | |
cat <<-EOF | |
Usage: $APP_NAME [options] | |
$APP_NAME --bash --pod "my-app" --namespace "default" | |
Helps you execute a shell inside a running pod, using fzf to help | |
you choose among existing options (namespaces, pods). | |
fzf allows you to fuzzy search among lists of namespaces or options | |
and is a pre-requisite for this script to work. | |
Options: | |
-h, --help This message. | |
-v, --version Version information. | |
-x, --debug Displays debug information using -x to | |
execute this script. Prints line by line | |
instructions. | |
--bash, --sh What shell/binary to execute. | |
-p, --pod <pod> Name of the pod to execute shell. | |
-n, --namespace <name> Namespace the pod is into. If none | |
is passed, fzf is used to choose among | |
available. | |
Bugs and/or suggestions to $APP_AUTHOR. | |
EOF | |
} | |
# Usage: main "#@" | |
main() | |
{ | |
while : | |
do | |
case "${1:-}" in | |
-h | --help) | |
display_help | |
exit 1 | |
;; | |
-v | --version) | |
echo "$APP_VERSION" | |
exit 1 | |
;; | |
-x | --debug) | |
set -x | |
;; | |
-n | -ns | --ns | --namespace) | |
OPTION_NAMESPACE="$2" | |
shift | |
;; | |
--sh) | |
OPTION_SHELL="/bin/sh" | |
;; | |
--bash) | |
OPTION_SHELL="/bin/bash" | |
;; | |
-p | --pod) | |
OPTION_POD="$2" | |
shift | |
;; | |
-?*) | |
echo "Error: Unknown option '$1'." >&2 | |
exit 2 | |
;; | |
*) | |
break | |
;; | |
esac | |
shift | |
done | |
# No namespace given, choose one | |
if empty "$OPTION_NAMESPACE" | |
then | |
OPTION_NAMESPACE="$(choose_namespace)" | |
fi | |
# No pod given, choose one | |
if empty "$OPTION_POD" | |
then | |
OPTION_POD="$(choose_pod "$OPTION_NAMESPACE")" | |
fi | |
if pod_not_running "$OPTION_POD" | |
then | |
echo "Error: '$OPTION_POD' is not running." >&2 | |
exit 3 | |
fi | |
enter_shell "$OPTION_POD" "$OPTION_SHELL" | |
return 0 | |
} | |
assert_env | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment