Skip to content

Instantly share code, notes, and snippets.

@emmeowzing
Last active November 18, 2022 19:40
Show Gist options
  • Save emmeowzing/b9425e3cad33f871e278d135ea8bad1a to your computer and use it in GitHub Desktop.
Save emmeowzing/b9425e3cad33f871e278d135ea8bad1a to your computer and use it in GitHub Desktop.
Switch Rancher clusters from your terminal, updating / merging your kube config
#! /usr/bin/env bash
# Connect to one of our clusters via Rancher's CLI.
set -e
_RANCHER_URL="${1:-$RANCHER_URL}"
_RANCHER_TOKEN="${2:-$RANCHER_TOKEN}"
DEFAULT_CLUSTER="${3:-development}
##
# Print an error message to stderr.
_error()
{
if [ $# -ne 1 ]
then
printf "Expected 1 argument to \`_error\`, received %s.\\n" "$#" >&2
exit 1
fi
local message
message="$1"
printf "\e[2m\e[1mERROR\e[0m\e[2m: %s\e[0m\\n" "$message" >&2
}
##
# Print a warning message to stderr.
_warning()
{
if [ $# -ne 1 ]
then
_error "Expected 1 argument to \`_warning\`, received $#.\\n"
return 1
fi
local message
message="$1"
printf "\e[2m\e[1mWARNING\e[0m\e[2m: %s\e[0m\\n" "$message" >&2
}
##
# Get a user's response on a question to set environment variables.
# Call like `X="$(response "Enter your name: " "Emma")"`
# To set a default value on `X` if the user just hits enter.
response()
{
if [ $# -eq 0 ]
then
_error "Must submit at least 2 arguments to \`response\` function for IO."
return 1
elif [ $# -gt 2 ]
then
_warning "received >2 arguments at response function, ignoring extra arguments"
fi
question="$1"
default="$2"
read -r -p "$question" var
if [ "$var" ]
then
printf "%s" "$var"
else
if [ "$default" ]
then
_warning "Defaulting to $default"
else
_warning "Attempted to default, but no value given, returning \"\""
fi
printf "%s" "$default"
fi
return 0
}
if command -v pass >/dev/null && [ -z "$_RANCHER_TOKEN" ]; then
_RANCHER_TOKEN="$(pass show rancher-token)"
elif [ -z "$_RANCHER_TOKEN" ]; then
_error "must set RANCHER_TOKEN environment variable or set up pass"
exit 1
fi
# Ensure we have some binaries this script requires.
if ! command -v kubectl >/dev/null; then
_error "must install the kubectl CLI: https://kubernetes.io/docs/tasks/tools/"
exit 1
fi
if ! command -v rancher >/dev/null; then
_error "must install the Rancher CLI: https://github.com/rancher/cli"
exit 1
fi
if ! command -v mapfile >/dev/null; then
_error "must upgrade bash (brew install bash)"
exit 1
fi
if ! command -v column >/dev/null; then
_error "must upgrade util-linux (apt install util-linux)"
exit 1
fi
# Ensure the expected directory structure is present.
if [ ! -d "$HOME"/.kube ]; then
_warning "setting up ~/.kube/config, directory doesn't exist"
mkdir "$HOME"/.kube
touch "$HOME"/.kube/config
elif [ -d "$HOME"/.kube ] && [ ! -f "$HOME"/.kube/config ]; then
_warning "setting up ~/.kube/config, directory doesn't exist"
touch "$HOME"/.kube/config
fi
##
# Switch rancher cluster contexts.
rancher_switch_cluster()
{
local cluster="$1"
printf "Info: Attempting to create ~/.kube/config for cluster \"%s\"\\n" "$cluster"
if ! rancher clusters kf "$cluster" > config.new; then
if [ -f config.new ]; then rm config.new; fi
exit 1
fi
# Flatten new kubeconfig into existing config and clean up.
cp "$HOME"/.kube/config "$HOME"/.kube/config.bak
KUBECONFIG=config.new:"$HOME"/.kube/config.bak kubectl config view --flatten > "$HOME"/.kube/config && \
rm "$HOME"/.kube/config.bak config.new && \
printf "Info: Successfully switched context to cluster \"%s\"\\n" "$cluster"
}
##
# Provide an interface to connect to a particular Rancher cluster.
rancher_select_cluster()
{
local cluster _cluster i n clusters selected_cluster
mapfile -t clusters < <(rancher clusters ls --format "{{ .Cluster.Name }}")
clusters+=("all")
i=1
n="${#clusters[@]}"
while true; do
printf "Select a cluster:\\n\\n"
for cluster in "${clusters[@]}"; do
printf "(%s) %s\\n" "$i" "$cluster"
(( i += 1 ))
done | column -t && printf "\\n"
selected_cluster="$(response "Select a cluster (by name or index): " "${DEFAULT_CLUSTER}")"
# Ensure this cluster is in the list (slow, linear search), either by index or name, and call a context switch.
i=1
for cluster in "${clusters[@]}"; do
if [ "$selected_cluster" = "$cluster" ]; then
if [ "$selected_cluster" != "all" ]; then
rancher_switch_cluster "$selected_cluster"
else
# Loop over all clusters and merge their configs to a dev's local kubeconfig, defaulting to ${DEFAULT_CLUSTER}.
for _cluster in "${clusters[@]}"; do
if [ "$_cluster" != "all" ]; then
rancher_switch_cluster "$_cluster"
fi
done
kubectl config use-context "${DEFAULT_CLUSTER}"
fi
return 0
elif [ "$selected_cluster" = "$i" ]; then
if [ "${clusters[$(( i - 1 ))]}" != "all" ]; then
rancher_switch_cluster "${clusters[$(( i - 1 ))]}"
else
for _cluster in "${clusters[@]}"; do
if [ "$_cluster" != "all" ]; then
rancher_switch_cluster "$_cluster"
fi
done
kubectl config use-context "${DEFAULT_CLUSTER}"
fi
return 0
elif [ "$i" -eq "$n" ]; then
_error "Cluster \"$selected_cluster\" does not exist, try again"
i=1
break
fi
(( i += 1 ))
done
done
}
##
# Log in to our Rancher server to connect to clusters.
rancher_login()
{
local token="$1"
local url="$2"
echo 1 | rancher login -t "$token" "$url" >/dev/null
}
rancher_login "$_RANCHER_TOKEN" "$_RANCHER_URL"
rancher_select_cluster
unset -v _RANCHER_TOKEN _RANCHER_URL DEFAULT_CLUSTER
unset -f _error _warning response rancher_select_cluster rancher_login rancher_switch_cluster
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment