87 lines
2.7 KiB
Bash
87 lines
2.7 KiB
Bash
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
SERVICE="${AIOS_V2_SERVICE:-aios-v2}"
|
|
RELEASE_ROOT="${AIOS_V2_RELEASE_ROOT:-/opt/aios/releases}"
|
|
CURRENT_LINK="${AIOS_V2_CURRENT_LINK:-/opt/aios/current}"
|
|
STATE_DIR="${AIOS_V2_STATE_DIR:-/var/lib/aios-v2}"
|
|
BACKUP_ROOT="${AIOS_V2_BACKUP_ROOT:-/var/backups/aios-v2}"
|
|
TARGET_RELEASE="${1:-}"
|
|
RESTORE_STATE="${AIOS_V2_RESTORE_STATE:-0}"
|
|
|
|
fail() {
|
|
echo "ERROR: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
[[ "${EUID}" -eq 0 ]] || fail "rollback must run as root"
|
|
[[ -n "$TARGET_RELEASE" ]] || fail "usage: $0 <release-name-or-absolute-path>"
|
|
|
|
if [[ "$TARGET_RELEASE" = /* ]]; then
|
|
TARGET_PATH="$(readlink -f "$TARGET_RELEASE")"
|
|
else
|
|
[[ "$TARGET_RELEASE" != *"/"* && "$TARGET_RELEASE" != "." && "$TARGET_RELEASE" != ".." ]] \
|
|
|| fail "invalid release name"
|
|
TARGET_PATH="$(readlink -f "$RELEASE_ROOT/$TARGET_RELEASE")"
|
|
fi
|
|
|
|
[[ -d "$TARGET_PATH/active-runtime/app" ]] || fail "target release is invalid: $TARGET_PATH"
|
|
[[ -f "$TARGET_PATH/deploy/aios-v2/healthcheck/check.sh" ]] \
|
|
|| fail "target release has no healthcheck"
|
|
|
|
PREVIOUS_PATH=""
|
|
if [[ -L "$CURRENT_LINK" ]]; then
|
|
PREVIOUS_PATH="$(readlink -f "$CURRENT_LINK")"
|
|
fi
|
|
|
|
STAMP="$(date -u +%Y%m%dT%H%M%SZ)"
|
|
BACKUP_DIR="$BACKUP_ROOT/rollback-$STAMP"
|
|
install -d -m 0750 "$BACKUP_DIR"
|
|
|
|
if [[ -d "$STATE_DIR" ]]; then
|
|
tar --xattrs --acls -C "$(dirname "$STATE_DIR")" \
|
|
-czf "$BACKUP_DIR/state-before-rollback.tar.gz" \
|
|
"$(basename "$STATE_DIR")"
|
|
fi
|
|
|
|
printf '%s\n' "$PREVIOUS_PATH" > "$BACKUP_DIR/previous-release.txt"
|
|
printf '%s\n' "$TARGET_PATH" > "$BACKUP_DIR/target-release.txt"
|
|
|
|
systemctl stop "$SERVICE"
|
|
ln -sfn "$TARGET_PATH" "${CURRENT_LINK}.next"
|
|
mv -Tf "${CURRENT_LINK}.next" "$CURRENT_LINK"
|
|
systemctl daemon-reload
|
|
systemctl start "$SERVICE"
|
|
|
|
if AIOS_V2_SERVICE="$SERVICE" \
|
|
AIOS_V2_STATE_DIR="$STATE_DIR" \
|
|
"$TARGET_PATH/deploy/aios-v2/healthcheck/check.sh"; then
|
|
echo "ROLLBACK_COMPLETE target=$TARGET_PATH backup=$BACKUP_DIR"
|
|
exit 0
|
|
fi
|
|
|
|
echo "Target release failed healthcheck; restoring previous release." >&2
|
|
systemctl stop "$SERVICE" || true
|
|
|
|
if [[ -n "$PREVIOUS_PATH" && -d "$PREVIOUS_PATH" ]]; then
|
|
ln -sfn "$PREVIOUS_PATH" "${CURRENT_LINK}.previous"
|
|
mv -Tf "${CURRENT_LINK}.previous" "$CURRENT_LINK"
|
|
fi
|
|
|
|
if [[ "$RESTORE_STATE" == "1" && -f "$BACKUP_DIR/state-before-rollback.tar.gz" ]]; then
|
|
rm -rf "$STATE_DIR"
|
|
tar --xattrs --acls -C "$(dirname "$STATE_DIR")" \
|
|
-xzf "$BACKUP_DIR/state-before-rollback.tar.gz"
|
|
fi
|
|
|
|
systemctl daemon-reload
|
|
systemctl start "$SERVICE" || true
|
|
|
|
if [[ -n "$PREVIOUS_PATH" && -x "$PREVIOUS_PATH/deploy/aios-v2/healthcheck/check.sh" ]]; then
|
|
AIOS_V2_SERVICE="$SERVICE" \
|
|
AIOS_V2_STATE_DIR="$STATE_DIR" \
|
|
"$PREVIOUS_PATH/deploy/aios-v2/healthcheck/check.sh" || true
|
|
fi
|
|
|
|
fail "rollback target failed; previous release restored; evidence=$BACKUP_DIR"
|