#!/bin/bash helm_update() { if [[ "${HELM}" == "helm_v3" ]]; then LINE="$(${HELM} ls --all -f "^${NAME}\$" --namespace ${TARGET_NAMESPACE} --output json | jq -r "${JQ_CMD}" | tr '[:upper:]' '[:lower:]')" else LINE="$(${HELM} ls --all "^${NAME}\$" --output json | jq -r "${JQ_CMD}" | tr '[:upper:]' '[:lower:]')" fi IFS=, read -r INSTALLED_VERSION STATUS _ <<<${LINE} VALUES="" for VALUES_FILE in /config/*.yaml; do VALUES="${VALUES} --values ${VALUES_FILE}" done # Uninstall or delete chart if asked to delete and the chart was found; otherwise no-op if [[ "$1" = "delete" ]]; then if [[ -z "${INSTALLED_VERSION}" ]]; then echo "No ${HELM} chart installed; nothing to delete" >> ${TERM_LOG} exit fi if [[ "${HELM}" == "helm_v3" ]]; then echo "Uninstalling ${HELM} chart" >> ${TERM_LOG} ${HELM} uninstall ${NAME} --namespace ${TARGET_NAMESPACE} --wait || true else echo "Deleting and purging ${HELM} chart" >> ${TERM_LOG} ${HELM} delete ${NAME} || true ${HELM} "$@" --purge ${NAME} fi exit fi # No current version and status, safe to install if [[ "${INSTALLED_VERSION}" =~ ^(|null)$ ]] && [[ "${STATUS}" =~ ^(|null)$ ]]; then echo "Installing ${HELM} chart" >> ${TERM_LOG} ${HELM} "$@" ${NAME_ARG} ${NAME} "${CHART}" ${CA_FILE_ARG} ${TIMEOUT_ARG} ${VALUES} exit fi # If a previous helm_v3 operation was interrupted unexpectedly, set it to failed. if [[ "${STATUS}" =~ ^(pending-install|pending-upgrade|pending-rollback)$ ]] && [[ "${HELM}" == "helm_v3" ]]; then echo Previous helm job was interrupted, updating status from ${STATUS} to failed echo "Resetting ${HELM} release status from '${STATUS}' to 'failed'" >> ${TERM_LOG} ${HELM} set-status ${NAME} failed --namespace ${TARGET_NAMESPACE} # Upgrades can be retried; install and rollback will be handled as failure below. # If this upgrade also fails, retries of the job will handle that as failure due to the release state change. if [[ "${STATUS}" == "pending-upgrade" ]]; then echo "Retrying upgrade of ${HELM} chart" >> ${TERM_LOG} echo "Retrying upgrade of ${NAME}" shift 1 ${HELM} upgrade "$@" ${NAME} "${CHART}" ${CA_FILE_ARG} ${TIMEOUT_ARG} ${VALUES} exit else STATUS=failed fi fi # Upgrade only if the chart is already deployed if [[ "${STATUS}" == "deployed" ]]; then echo "Already installed ${NAME}" if [[ "${HELM}" == "helm_v3" ]]; then ${HELM} mapkubeapis ${NAME} --namespace ${TARGET_NAMESPACE} else ${HELM} mapkubeapis ${NAME} --v2 fi echo "Upgrading ${HELM} chart" >> ${TERM_LOG} echo "Upgrading ${NAME}" shift 1 ${HELM} upgrade "$@" ${NAME} "${CHART}" ${CA_FILE_ARG} ${TIMEOUT_ARG} ${VALUES} exit fi # The chart is in a bad state; try uninstalling it first if [[ "${STATUS}" =~ ^(deleted|failed|null|unknown)$ ]]; then if [[ "${FAILURE_POLICY:-reinstall}" == "reinstall" ]]; then if [[ "${HELM}" == "helm_v3" ]]; then echo "Uninstalling ${STATUS} ${HELM} chart" >> ${TERM_LOG} ${HELM} uninstall ${NAME} --namespace ${TARGET_NAMESPACE} --wait else echo "Purging ${STATUS} ${HELM} chart" >> ${TERM_LOG} ${HELM} "$@" --purge ${NAME} fi echo Deleted # Try installing now that we've uninstalled echo "Installing ${HELM} chart" >> ${TERM_LOG} ${HELM} "$@" ${NAME_ARG} ${NAME} "${CHART}" ${CA_FILE_ARG} ${TIMEOUT_ARG} ${VALUES} exit else echo "Release status is '${STATUS}' and failure policy is '${FAILURE_POLICY}', not 'reinstall'; waiting for operator intervention" >> ${TERM_LOG} echo "Release status is '${STATUS}' and failure policy is '${FAILURE_POLICY}', not 'reinstall'; waiting for operator intervention" exit 1 fi fi # No special status handling necessary, do whatever we were asked to do echo "Installing ${HELM} chart" >> ${TERM_LOG} ${HELM} "$@" ${NAME_ARG} ${NAME} "${CHART}" ${CA_FILE_ARG} ${TIMEOUT_ARG} ${VALUES} } helm_repo_init() { # if the chart is url skip repo update if grep -q -e "https\?://" <<< "${CHART}"; then echo "chart path is a url, skipping repo update" ${HELM} repo remove stable || true return fi if [[ "${HELM}" == "helm_v3" ]]; then if [[ ${CHART} == stable/* ]]; then ${HELM} repo add ${CA_FILE_ARG} stable ${STABLE_REPO_URL} ${HELM} repo update fi else ${HELM} repo update --strict || ${HELM} repo remove stable fi if [[ -n "${REPO}" ]]; then if [[ -f "${AUTH_DIR}/username" ]] && [[ -f "${AUTH_DIR}/password" ]]; then if [[ "${HELM}" == "helm_v2" ]]; then echo "Repo authentication is not supported with v2 charts" >> ${TERM_LOG} echo "Repo authentication is not supported with v2 charts" exit 1 fi if [[ "${AUTH_PASS_CREDENTIALS}" == "true" ]]; then PASS_CREDENTIALS_ARG="--pass-credentials" fi cat ${AUTH_DIR}/password | ${HELM} repo add ${CA_FILE_ARG} ${PASS_CREDENTIALS_ARG} --username "$(cat ${AUTH_DIR}/username)" --password-stdin ${NAME%%/*} ${REPO} else ${HELM} repo add ${CA_FILE_ARG} ${NAME%%/*} ${REPO} fi ${HELM} repo update fi } helm_content_decode() { set -e ENC_CHART_PATH="/chart/${NAME}.tgz.base64" CHART_PATH="/tmp/${NAME}.tgz" if [[ ! -f "${ENC_CHART_PATH}" ]]; then return fi base64 -d ${ENC_CHART_PATH} > ${CHART_PATH} CHART=${CHART_PATH} set +e } export CA_FILE=/config/ca-file.pem export CA_DIR=/ca-files export AUTH_DIR=/auth export TERM_LOG=/dev/termination-log export SSL_CERT_FILE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt export SSL_CERT_DIR=/etc/ssl/certs export HELM_TLS_CA_CERT=${SSL_CERT_FILE} HELM="helm_v3" NAME_ARG="" CA_FILE_ARG="" TIMEOUT_ARG="" PASS_CREDENTIALS_ARG="" JQ_CMD='"\(.[0].chart),\(.[0].status)"' set -e -v if [[ ${KUBERNETES_SERVICE_HOST} =~ .*:.* ]]; then echo "KUBERNETES_SERVICE_HOST is using IPv6" CHART="${CHART//%\{KUBERNETES_API\}%/[${KUBERNETES_SERVICE_HOST}]:${KUBERNETES_SERVICE_PORT}}" else CHART="${CHART//%\{KUBERNETES_API\}%/${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}}" fi set +v -x if [[ "${BOOTSTRAP}" != "true" ]]; then tiller --listen=127.0.0.1:44134 --storage=secret & export HELM_HOST=127.0.0.1:44134 helm_v2 init --skip-refresh --client-only --stable-repo-url ${STABLE_REPO_URL} V2_CHART_EXISTS=$(timeout -s KILL 30 helm_v2 ls --all "^${NAME}\$" --output json | jq -r '.Releases | length') fi if [[ "${V2_CHART_EXISTS}" == "1" ]] || [[ "${HELM_VERSION}" == "v2" ]]; then if [[ "${BOOTSTRAP}" == "true" ]]; then echo "Can't bootstrap ${HELM} chart" >> ${TERM_LOG} echo "Error: bootstrap flag can't be set with helm version 2 charts, please remove the bootstrap flag and update the chart" exit 1 fi HELM="helm_v2" NAME_ARG="--name" JQ_CMD='"\(.Releases[0].AppVersion),\(.Releases[0].Status)"' fi shopt -s nullglob if [[ -f "${CA_FILE}" ]]; then echo >> /tmp/ca-file.pem cat "${CA_FILE}" >> /tmp/ca-file.pem fi for CA_FILE in ${CA_DIR}/*; do echo >> /tmp/ca-file.pem cat "${CA_FILE}" >> /tmp/ca-file.pem done if [[ -f "/tmp/ca-file.pem" ]]; then CA_FILE_ARG="--ca-file /tmp/ca-file.pem" fi if [[ -n "${TIMEOUT}" ]]; then if [[ "${HELM}" == "helm_v3" ]]; then TIMEOUT_ARG="--timeout ${TIMEOUT}" else echo "Warning: timeout flag can't be set with version 2 charts, using default timeout" fi fi helm_content_decode if [[ "$1" != "delete" ]]; then helm_repo_init fi helm_update "$@"