#!/bin/bash

helm_update() {
	LINE="$(${HELM} ls --all -f "^${NAME}\$" --namespace ${TARGET_NAMESPACE} --output json | jq -r "${JQ_CMD}" | tr '[:upper:]' '[:lower:]')"
	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
		echo "Uninstalling ${HELM} chart" >> ${TERM_LOG}
		${HELM} uninstall ${NAME} --namespace ${TARGET_NAMESPACE} --wait || true
		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} ${INSECURE_TLS_ARG} ${PLAIN_HTTP_ARG} ${TIMEOUT_ARG} ${VALUES}
		exit
	fi

	# If a previous helm operation was interrupted unexpectedly, set it to failed.
	if [[ "${STATUS}" =~ ^(pending-install|pending-upgrade|pending-rollback|uninstalling)$ ]]; 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} ${INSECURE_TLS_ARG} ${PLAIN_HTTP_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}"
		${HELM} mapkubeapis ${NAME} --namespace ${TARGET_NAMESPACE}

		echo "Upgrading ${HELM} chart" >> ${TERM_LOG}
		echo "Upgrading ${NAME}"
		shift 1
		${HELM} upgrade "$@" ${NAME} "${CHART}" ${CA_FILE_ARG} ${INSECURE_TLS_ARG} ${PLAIN_HTTP_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
			echo "Uninstalling ${STATUS} ${HELM} chart" >> ${TERM_LOG}
			${HELM} uninstall ${NAME} --namespace ${TARGET_NAMESPACE} --wait
			echo Deleted
			# Try installing now that we've uninstalled
			echo "Installing ${HELM} chart" >> ${TERM_LOG}
			${HELM} "$@" ${NAME_ARG} ${NAME} "${CHART}" ${CA_FILE_ARG} ${INSECURE_TLS_ARG} ${PLAIN_HTTP_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} ${INSECURE_TLS_ARG} ${PLAIN_HTTP_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 [[ ${CHART} == stable/* ]]; then
		${HELM} repo add ${CA_FILE_ARG} ${INSECURE_TLS_ARG} stable ${STABLE_REPO_URL}
		${HELM} repo update
	fi

	if [[ -n "${REPO}" ]]; then
		if [[ -f "${AUTH_DIR}/username" ]] && [[ -f "${AUTH_DIR}/password" ]]; then
			if [[ "${AUTH_PASS_CREDENTIALS}" == "true" ]]; then
				PASS_CREDENTIALS_ARG="--pass-credentials"
			fi
			cat ${AUTH_DIR}/password | ${HELM} repo add ${CA_FILE_ARG} ${INSECURE_TLS_ARG} ${PASS_CREDENTIALS_ARG} --username "$(cat ${AUTH_DIR}/username)" --password-stdin ${NAME%%/*} ${REPO}
		elif [[ -f "${AUTH_DIR}/tls.crt" ]] && [[ -f "${AUTH_DIR}/tls.key" ]]; then
			if [[ "${AUTH_PASS_CREDENTIALS}" == "true" ]]; then
				PASS_CREDENTIALS_ARG="--pass-credentials"
			fi
			${HELM} repo add ${CA_FILE_ARG} ${INSECURE_TLS_ARG} ${PASS_CREDENTIALS_ARG} --cert-file ${AUTH_DIR}/tls.crt --key-file ${AUTH_DIR}/tls.key ${NAME%%/*} ${REPO}
		else
			${HELM} repo add ${CA_FILE_ARG} ${INSECURE_TLS_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"
NAME_ARG=""
CA_FILE_ARG=""
INSECURE_TLS_ARG=""
PLAIN_HTTP_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 [[ "${HELM_VERSION}" == "v2" ]]; then
	echo "Helm v2 is EOL effective 2020-11-13; upgrade your chart to helm v3" >> ${TERM_LOG}
	echo "Helm v2 is EOL effective 2020-11-13; upgrade your chart to helm v3"
	exit 64
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 [[ "${INSECURE_SKIP_TLS_VERIFY}" == "true" ]]; then
  INSECURE_TLS_ARG="--insecure-skip-tls-verify"
fi

if [[ "${PLAIN_HTTP}" == "true" ]]; then
  PLAIN_HTTP_ARG="--plain-http"
fi

if [[ -n "${TIMEOUT}" ]]; then
	TIMEOUT_ARG="--timeout ${TIMEOUT}"
fi

helm_content_decode
if [[ "$1" != "delete" ]]; then
	helm_repo_init
fi
helm_update "$@"