From 8e72577f498df1e767564bca10ccaeedabdf0d22 Mon Sep 17 00:00:00 2001 From: Brad Davidson Date: Tue, 8 Jun 2021 14:31:56 -0700 Subject: [PATCH] Add support for extended install/upgrade timeouts and handle failed/pending states (#27) * Consistently use double brackets for tests * Consistently wrap variables in curly braces * Eliminate unnecessary cut/cat/sed that can be done in pure bash * Handle pending-upgrade chart status * Add timeout support; fix whitespace * Update build image toolchain Signed-off-by: Brad Davidson --- Dockerfile.dapper | 19 ++------ entry | 111 +++++++++++++++++++++++++-------------------- package/Dockerfile | 1 + 3 files changed, 67 insertions(+), 64 deletions(-) diff --git a/Dockerfile.dapper b/Dockerfile.dapper index 051fc07..8f4d9f9 100644 --- a/Dockerfile.dapper +++ b/Dockerfile.dapper @@ -1,28 +1,17 @@ -FROM golang:1.15-alpine +FROM golang:1.16-alpine3.12 ARG DAPPER_HOST_ARCH ENV ARCH $DAPPER_HOST_ARCH RUN apk -U add bash git gcc musl-dev docker vim less file curl wget ca-certificates -RUN go get -d golang.org/x/lint/golint && \ - git -C /go/src/golang.org/x/lint/golint checkout -b current 738671d3881b9731cc63024d5d88cf28db875626 && \ - go install golang.org/x/lint/golint && \ - rm -rf /go/src /go/pkg -RUN go get -d github.com/alecthomas/gometalinter && \ - git -C /go/src/github.com/alecthomas/gometalinter checkout -b current v3.0.0 && \ - go install github.com/alecthomas/gometalinter && \ - gometalinter --install && \ - rm -rf /go/src /go/pkg -RUN go get -d github.com/rancher/trash && \ - git -C /go/src/github.com/rancher/trash checkout -b current v0.2.7 && \ - go install github.com/rancher/trash && \ - rm -rf /go/src /go/pkg +RUN if [ "$(go env GOARCH)" = "amd64" ]; then \ + curl -sL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s v1.40.0; \ + fi ENV DAPPER_ENV REPO TAG DRONE_TAG ENV DAPPER_SOURCE /go/src/github.com/k3s-io/klipper-helm/ ENV DAPPER_OUTPUT ./bin ./dist ENV DAPPER_DOCKER_SOCKET true -ENV TRASH_CACHE ${DAPPER_SOURCE}/.trash-cache ENV HOME ${DAPPER_SOURCE} WORKDIR ${DAPPER_SOURCE} diff --git a/entry b/entry index 271263e..911ff1f 100755 --- a/entry +++ b/entry @@ -1,79 +1,83 @@ #!/bin/bash helm_update() { - if [ "$HELM" == "helm_v3" ]; then - LINE="$($HELM ls -f "^$NAME\$" --namespace $TARGET_NAMESPACE --output json | jq -r "$JQ_CMD" | tr '[:upper:]' '[:lower:]')" + 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:]')" + LINE="$(${HELM} ls --all "^${NAME}\$" --output json | jq -r "${JQ_CMD}" | tr '[:upper:]' '[:lower:]')" fi - INSTALLED_VERSION=$(echo $LINE | cut -f1 -d,) - STATUS=$(echo $LINE | cut -f2 -d,) + IFS=, read -r INSTALLED_VERSION STATUS _ <<<${LINE} VALUES="" for VALUES_FILE in /config/*.yaml; do - VALUES="$VALUES --values $VALUES_FILE" + VALUES="${VALUES} --values ${VALUES_FILE}" done - if [ "$1" = "delete" ]; then - if [ -z "$INSTALLED_VERSION" ]; then + # 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 exit fi - if [ "$HELM" == "helm_v3" ]; then - $HELM uninstall $NAME --namespace $TARGET_NAMESPACE|| true + if [[ "${HELM}" == "helm_v3" ]]; then + ${HELM} uninstall ${NAME} --namespace ${TARGET_NAMESPACE} || true else - $HELM delete $NAME || true - $HELM "$@" --purge $NAME + ${HELM} delete ${NAME} || true + ${HELM} "$@" --purge ${NAME} fi exit fi - if [ -z "$INSTALLED_VERSION" ] && [ -z "$STATUS" ]; then - $HELM "$@" $NAME_ARG $NAME $CHART $VALUES + # No current version and status, safe to install + if [[ "${INSTALLED_VERSION}" =~ ^(|null)$ ]] && [[ "${STATUS}" =~ ^(|null)$ ]]; then + ${HELM} "$@" ${NAME_ARG} ${NAME} ${CHART} ${TIMEOUT_ARG} ${VALUES} exit fi - # Upgrade only if the status is already deployed - if [ "$STATUS" = "deployed" ]; then - echo Already installed $NAME, upgrading + # Upgrade only if the status is already deployed, or if a previous upgrade was interrupted + if [[ "${STATUS}" =~ ^(deployed|pending-upgrade)$ ]]; then + echo Already installed ${NAME}, upgrading shift 1 - $HELM upgrade "$@" $NAME $CHART $VALUES + ${HELM} upgrade "$@" ${NAME} ${CHART} ${TIMEOUT_ARG} ${VALUES} exit fi - if [ "$STATUS" = "failed" ] || [ "$STATUS" = "deleted" ]; then - if [ "$HELM" == "helm_v3" ]; then - $HELM uninstall $NAME --namespace $TARGET_NAMESPACE + # The chart is in a bad state; try uninstalling it first + if [[ "${STATUS}" =~ ^(deleted|failed|null|unknown)$ ]]; then + if [[ "${HELM}" == "helm_v3" ]]; then + ${HELM} uninstall ${NAME} --namespace ${TARGET_NAMESPACE} else - $HELM "$@" --purge $NAME + ${HELM} "$@" --purge ${NAME} fi echo Deleted - $HELM "$@" $NAME_ARG $NAME $CHART $VALUES + # Try installing now that we've uninstalled + ${HELM} "$@" ${NAME_ARG} ${NAME} ${CHART} ${TIMEOUT_ARG} ${VALUES} exit fi - $HELM "$@" $NAME_ARG $NAME $CHART $VALUES + # No special status handling necessary, do whatever we were asked to do + ${HELM} "$@" ${NAME_ARG} ${NAME} ${CHART} ${TIMEOUT_ARG} ${VALUES} } helm_repo_init() { # if the chart is url skip repo update - if grep -q -e "https\?://" <<< "$CHART"; then + if grep -q -e "https\?://" <<< "${CHART}"; then echo "chart path is a url, skipping repo update" - $HELM repo remove stable || true + ${HELM} repo remove stable || true return fi - if [ "$HELM" == "helm_v3" ]; then - if [[ $CHART == stable/* ]]; then - $HELM repo add stable $STABLE_REPO_URL - $HELM repo update + if [[ "${HELM}" == "helm_v3" ]]; then + if [[ ${CHART} == stable/* ]]; then + ${HELM} repo add stable ${STABLE_REPO_URL} + ${HELM} repo update fi else - $HELM repo update --strict || $HELM repo remove stable + ${HELM} repo update --strict || ${HELM} repo remove stable fi - if [ -n "$REPO" ]; then - $HELM repo add ${NAME%%/*} $REPO - $HELM repo update + if [[ -n "${REPO}" ]]; then + ${HELM} repo add ${NAME%%/*} ${REPO} + ${HELM} repo update fi } @@ -81,48 +85,57 @@ helm_content_decode() { set -e ENC_CHART_PATH="/chart/${NAME}.tgz.base64" CHART_PATH="/${NAME}.tgz" - if [ ! -f "${ENC_CHART_PATH}" ]; then + if [[ ! -f "${ENC_CHART_PATH}" ]]; then return fi - cat ${ENC_CHART_PATH} | base64 -d > ${CHART_PATH} + base64 -d ${ENC_CHART_PATH} > ${CHART_PATH} CHART=${CHART_PATH} set +e } HELM="helm_v3" NAME_ARG="" +TIMEOUT_ARG="" JQ_CMD='"\(.[0].app_version),\(.[0].status)"' set -e -v -CHART=$(sed -e "s/%{KUBERNETES_API}%/${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}/g" <<< "${CHART}") +CHART="${CHART//%\{KUBERNETES_API\}%/${KUBERNETES_SERVICE_HOST}:${KUBERNETES_SERVICE_PORT}}" set +v -x cp /var/run/secrets/kubernetes.io/serviceaccount/ca.crt /usr/local/share/ca-certificates/ update-ca-certificates -if [ "$BOOTSTRAP" != "true" ]; then - tiller --listen=127.0.0.1:44134 --storage=secret & - export HELM_HOST=127.0.0.1:44134 +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 - EXIST=$(helm_v2 ls --all "^$NAME\$" --output json | jq -r '.Releases | length') + helm_v2 init --skip-refresh --client-only --stable-repo-url ${STABLE_REPO_URL} + V2_CHART_EXISTS=$(helm_v2 ls --all "^${NAME}\$" --output json | jq -r '.Releases | length') fi -if [ "$EXIST" == "1" ] || [ "$HELM_VERSION" == "v2" ]; then - if [ "$BOOTSTRAP" == "true" ]; then - 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 +if [[ "${V2_CHART_EXISTS}" == "1" ]] || [[ "${HELM_VERSION}" == "v2" ]]; then + if [[ "${BOOTSTRAP}" == "true" ]]; then + 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 +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 + shopt -s nullglob helm_content_decode -if [ "$1" != "delete" ]; then - helm_repo_init +if [[ "$1" != "delete" ]]; then + helm_repo_init fi helm_update "$@" diff --git a/package/Dockerfile b/package/Dockerfile index 8af3cec..eeba336 100644 --- a/package/Dockerfile +++ b/package/Dockerfile @@ -12,3 +12,4 @@ COPY --from=extract /usr/bin/helm_v2 /usr/bin/helm_v3 /usr/bin/tiller /usr/bin/ COPY entry /usr/bin/ ENTRYPOINT ["entry"] ENV STABLE_REPO_URL=https://charts.helm.sh/stable/ +ENV TIMEOUT=