Skip to content

Instantly share code, notes, and snippets.

@anapsix
Last active October 28, 2020 02:43
Show Gist options
  • Save anapsix/eff8a9248fc5ba446fcb373daae143b9 to your computer and use it in GitHub Desktop.
Save anapsix/eff8a9248fc5ba446fcb373daae143b9 to your computer and use it in GitHub Desktop.
Helm CLI wrapper making it easier to work with multiple clusters when using TLS-enabled Tiller
#!/usr/bin/env bash
#
# this script is a helpful wrapper for Helm CLI, when using TLS enabled Tiller
# See https://github.com/helm/helm/blob/master/docs/tiller_ssl.md
#
# === NOTE ===
# It will attempt to download Helm binary to match Helm Server version
# if it's not found locally
#
# === INSTRUCTIONS ===
# save this somewhere in your PATH (e.g. /usr/local/bin/) as helm_tls_wrapper.sh
# and add shell alias (so that shell-completion works without any additional changes)
# alias helm=helm_tls_wrapper.sh
#
# save your TLS certificates in ${HELM_HOME}/tls/${K8S_CONTEXT}/
# as ca.pem, cert.pem, and key.pem
#
# === LICENSE ===
# Copyright (C) 2019-2020 Anastas Dancha (aka @anapsix)
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
set -u
set -o pipefail
: ${HELM_HOME:=~/.helm}
: ${HELM_BIN_DIR:=$HELM_HOME/bin}
: ${HELM_BIN_FALLBACK:=helm_v2.16.5}
: ${KUBECONFIG:=${HOME}/.kube/config}
: ${HELM_VERSION:='unset'}
: ${HELM_VERSION_CLIENT:='unset'}
: ${HELM_VERSION_SERVER:='unset'}
HELM_ARGS=()
export PATH="${HELM_BIN_DIR}:$PATH"
info() {
if [[ ${QUIET:-0} -eq 0 ]] || [[ ${DEBUG:-0} -eq 1 ]]; then
if [[ "${2:-0}" == "-" ]]; then
echo >&2 -e "$1"
else
echo >&2 -e "\e[92mINFO:\e[0m $1"
fi
fi
}
warn() {
if [[ ${QUIET:-0} -eq 0 ]] || [[ ${DEBUG:-0} -eq 1 ]]; then
if [[ "${2:-0}" == "-" ]]; then
echo >&2 -e "$1"
else
echo >&2 -e "\e[33mWARNING:\e[0m $1"
fi
fi
}
debug(){
if [[ ${DEBUG:-0} -eq 1 ]]; then
if [[ "${2:-0}" == "-" ]]; then
echo >&2 -e "$1"
else
echo >&2 -e "\e[95mDEBUG:\e[0m $1"
fi
fi
}
error(){
local msg="$1"
local exit_code="${2:-1}"
echo >&2 -e "\e[91mERROR:\e[0m $1"
if [[ "${exit_code}" != "-" ]]; then
exit ${exit_code}
fi
}
getval() {
local x="${1%%=*}"
if [[ "$x" = "$1" ]]; then
echo "${2}"
return 2
else
echo "${1##*=}"
return 1
fi
}
## Get CLI arguments
while [[ $# -gt 0 ]]; do
case "$1" in
-d|--debug)
DEBUG=1
shift 1
;;
--tls)
USE_TLS=1
shift 1
;;
--kube-context|--kube-context=*)
K8S_CONTEXT_ARG="$(getval "$1" "${2:-}")"
shift $?
HELM_ARGS+=(--kube-context=${K8S_CONTEXT_ARG})
;;
--helm-version|--helm-version=*)
HELM_VERSION="$(getval "$1" "${2:-}")"
shift $?
;;
*)
HELM_ARGS+=(${1})
shift 1
;;
esac
done
set -e
if [[ "${K8S_CONTEXT_ARG:-unset}" == "unset" ]]; then
K8S_CONTEXT="$(grep current-context "${KUBECONFIG}" | awk '{print $NF}')"
else
K8S_CONTEXT="${K8S_CONTEXT_ARG}"
fi
warn "K8S_CONTEXT: ${K8S_CONTEXT}"
export K8S_CONTEXT
if [[ "${HELM_VERSION}" == "unset" ]]; then
HELM_BIN="${HELM_BIN_FALLBACK}"
else
debug "HELM Version: ${HELM_VERSION}"
HELM_BIN="${HELM_BIN_DIR}/helm_${HELM_VERSION}"
debug "HELM_BIN: ${HELM_BIN}"
fi
if [[ ${USE_TLS:-0} -eq 1 ]]; then
export HELM_TLS_CA_CERT="${HELM_HOME}/tls/${K8S_CONTEXT}/ca.pem"
export HELM_TLS_CERT="${HELM_HOME}/tls/${K8S_CONTEXT}/cert.pem"
export HELM_TLS_KEY="${HELM_HOME}/tls/${K8S_CONTEXT}/key.pem"
export HELM_TLS_ENABLE="true"
if [[ ${DEBUG:-0} -eq 1 ]]; then
debug "TLS Environmental variables below"
echo >&2 export HELM_TLS_ENABLE=\"true\"
echo >&2 export HELM_TLS_CA_CERT=\"${HELM_HOME}/tls/${K8S_CONTEXT}/ca.pem\"
echo >&2 export HELM_TLS_CERT=\"${HELM_HOME}/tls/${K8S_CONTEXT}/cert.pem\"
echo >&2 export HELM_TLS_KEY=\"${HELM_HOME}/tls/${K8S_CONTEXT}/key.pem\"
fi
fi
get_helm_version() {
local version="$1"
local helm_arch
case $(uname) in
Darwin)
helm_arch="darwin-amd64"
;;
Linux)
helm_arch="linux-amd64"
;;
*)
error "$(uname) is not supported"
;;
esac
if [[ ! -d "${HELM_BIN_DIR}" ]]; then
mkdir -p "${HELM_BIN_DIR}"
fi
curl -sS "https://get.helm.sh/helm-${version}-${helm_arch}.tar.gz" \
| tar -xf- -O ${helm_arch}/helm > "${HELM_BIN_DIR}/helm_${version}"
chmod +x "${HELM_BIN_DIR}/helm_${version}"
}
version_check() {
local version_check="$(${HELM_BIN} --kube-context=${K8S_CONTEXT} version --short)"
local client_version="$(echo "${version_check}" | grep '^Client' | awk '{print $2}')"
local server_version="$(echo "${version_check}" | grep '^Server' | awk '{print $2}')"
debug "Helm Client version: ${client_version%%+*}"
warn "Helm Server version: ${server_version%%+*}"
HELM_VERSION_CLIENT="${client_version%%+*}"
HELM_VERSION_SERVER="${server_version%%+*}"
if [[ -z ${HELM_VERSION_SERVER:-} ]]; then
error "Could not detect Helm server component, verify kube-context and/or network.."
fi
HELM_BIN="${HELM_BIN_DIR}/helm_${HELM_VERSION_SERVER}"
if [[ "${HELM_VERSION_CLIENT}" != "${HELM_VERSION_SERVER}" ]]; then
if [[ ! -e "${HELM_BIN}" ]]; then
warn "Helm Client/Server version mismatch: client ${HELM_VERSION_CLIENT} vs. server ${HELM_VERSION_SERVER}"
warn "Helm client version \"${HELM_VERSION_SERVER}\" is not found locally.."
echo >&2 -n "Attempt to download version ${HELM_VERSION_SERVER}? [y/N] "
read GET_HELM
case "${GET_HELM:-n}" in
y|Y)
get_helm_version "${HELM_VERSION_SERVER}"
;;
*)
error "suit yourself, exiting.."
;;
esac
fi
fi
}
if [[ "$(which ${HELM_BIN} | wc -l | awk '{print $1}')" == 0 ]]; then
warn "Helm fallback binary ${HELM_BIN_FALLBACK#*_} is not found, getting it.."
get_helm_version ${HELM_BIN#*_}
fi
debug "HELM binary: ${HELM_BIN}"
version_check
debug "Helm arguments: ${HELM_ARGS[@]}"
if [[ ${DEBUG:-0} -eq 1 ]]; then
echo >&2 "${HELM_BIN} ${HELM_ARGS[@]}"
else
${HELM_BIN} ${HELM_ARGS[@]}
fi
@feksai
Copy link

feksai commented Feb 27, 2019

Thanks. Useful solution

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