Skip to content

Instantly share code, notes, and snippets.

@bitti
Last active June 19, 2024 01:06
Show Gist options
  • Save bitti/1ea6d80ecfa8872cef0fc8e5452cc62c to your computer and use it in GitHub Desktop.
Save bitti/1ea6d80ecfa8872cef0fc8e5452cc62c to your computer and use it in GitHub Desktop.
kubectl plugin/wrapper to match kubectl binary version to current cluster version
#!/bin/bash
set -e
cache=${XDG_CACHE_HOME:-$HOME/.cache}/kubectl-v
errors="$cache/errors-$$"
mkdir -p "$cache"
[[ $1 = "v" ]] && shift # Avoid recursive calls
get_sys() {
uname | tr '[:upper:]' '[:lower:]'
}
get_cpu() {
local -r machine_hardware_name=$(uname -m)
case "$machine_hardware_name" in
x86_64) echo amd64 ;;
powerpc64le|ppc64le) echo ppc64le ;;
aarch64) echo arm64 ;;
armv7l) echo arm ;;
*) echo "$machine_hardware_name" ;;
esac
}
fetch_kubectl() {
[[ -x $2 ]] && return
echo "Download kubectl $1"
local sys cpu
sys=$(get_sys)
cpu=$(get_cpu)
# ARM binaries not available before 1.20.0
if [[ $sys = "darwin" && $cpu = "arm64" && $(semver compare $1 v1.20.0) = -1 ]]; then
cpu="amd64"
fi
curl -L "https://storage.googleapis.com/kubernetes-release/release/$1/bin/${sys}/${cpu}/kubectl" -o "$2"
chmod +x "$2"
}
link_kubectl() {
ln -sf "$(basename "$1")" "$cache/$(basename "$2")"
}
fetch_kubectl_latest() {
kubectl_latest="$cache/kubectl-latest"
[[ -x $kubectl_latest ]] && return
local -r stable_version=$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)
local -r kubectl_stable="$cache/kubectl-${stable_version}"
fetch_kubectl "$stable_version" "$kubectl_stable"
link_kubectl "$kubectl_stable" "$kubectl_latest"
}
current_cluster_name() {
kubectl_cluster="$cache/kubectl-$($kubectl_default config view --minify -o jsonpath='{.clusters[].name}')"
echo ${cluster_name/*\//} # Remove path prefixes (i.e. from arn URIs)
}
kubectl_path_for_current_cluster() {
cluster_name=$($kubectl_default config view --minify -o jsonpath='{.clusters[].name}')
cluster_name=${cluster_name/*\//} # Remove path prefixes (i.e. from arn URIs)
echo "$cache/kubectl-$cluster_name"
}
fetch_kubectl_current() {
kubectl_path=$(kubectl_path_for_current_cluster)
[[ -x $kubectl_path ]] && return
local current_version
current_version=$($kubectl_default version --output=yaml 2> >(grep -v "version difference" >&2))
current_version=${current_version/*gitVersion: } # Remove preamble
current_version=${current_version%%-*} # Remove suffixes
kubectl_current="$cache/kubectl-$current_version"
fetch_kubectl "$current_version" "$kubectl_current"
link_kubectl "$kubectl_current" "$kubectl_path"
}
kubectl_default=${HOMEBREW_PREFIX:-/opt/homebrew}/bin/kubectl
[[ -x $kubectl_default ]] || { fetch_kubectl_latest && kubectl_default=$kubectl_latest; }
if [[ $1 = "config" ]]; then
$kubectl_default "$@"
else
if [[ $1 = "update" ]]; then
kubectl_path=$(kubectl_path_for_current_cluster)
rm $kubectl_path
echo "Updating kubectl for ${kubectl_path/*kubectl-/}..."
fetch_kubectl_current
$kubectl_path version
else
fetch_kubectl_current
$kubectl_path "$@"
fi
fi
@bitti
Copy link
Author

bitti commented Jun 12, 2022

Setup

Put content into a file in $PATH, and make executable

$ chmod +x kubectl-v

Usage

Use as a kubectl plugin by prefixing arguments with v. E.g.

$ kubectl v version

Or call kubectl-v in a kubectl wrapper script or alias

Gotchas

  • The --context argument is ignored to determine the cluster version, only the current-context is considered
  • Standard kubectl binaries before v1.13.0 are not compatible with macOS Montery. You need to use special builds with updated Golang-libs for these

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment