Skip to content

Instantly share code, notes, and snippets.

@augustohp
Last active August 23, 2023 02:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save augustohp/deebc619c515463b9df6f46d8c7376af to your computer and use it in GitHub Desktop.
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.
#!/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