update: add self-healing updater logs, lock, and status output
This commit is contained in:
parent
fba6c2c940
commit
1cdb2cb3f3
@ -60,6 +60,8 @@ Artifacts:
|
|||||||
- `/var/lib/ananke/last-shutdown-report.json`
|
- `/var/lib/ananke/last-shutdown-report.json`
|
||||||
- `/var/lib/ananke/reports/*.json` (historical per-run reports)
|
- `/var/lib/ananke/reports/*.json` (historical per-run reports)
|
||||||
- `/var/lib/ananke/runs.json` (timing history)
|
- `/var/lib/ananke/runs.json` (timing history)
|
||||||
|
- `/var/lib/ananke/update-last.env` (latest self-update result)
|
||||||
|
- `/var/log/ananke/update.log` (self-update execution log)
|
||||||
|
|
||||||
## Quick commands
|
## Quick commands
|
||||||
|
|
||||||
@ -83,6 +85,8 @@ Systemd control:
|
|||||||
sudo systemctl status ananke.service
|
sudo systemctl status ananke.service
|
||||||
sudo systemctl start ananke-bootstrap.service
|
sudo systemctl start ananke-bootstrap.service
|
||||||
sudo systemctl start ananke-update.service
|
sudo systemctl start ananke-update.service
|
||||||
|
sudo cat /var/lib/ananke/update-last.env
|
||||||
|
sudo tail -n 200 /var/log/ananke/update.log
|
||||||
```
|
```
|
||||||
|
|
||||||
## Config
|
## Config
|
||||||
|
|||||||
@ -2,12 +2,20 @@
|
|||||||
Description=Ananke Self-Update and Reinstall
|
Description=Ananke Self-Update and Reinstall
|
||||||
Wants=network-online.target
|
Wants=network-online.target
|
||||||
After=network-online.target
|
After=network-online.target
|
||||||
|
StartLimitIntervalSec=0
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
User=root
|
User=root
|
||||||
Group=root
|
Group=root
|
||||||
|
Environment=ANANKE_UPDATE_LOG_FILE=/var/log/ananke/update.log
|
||||||
|
Environment=ANANKE_UPDATE_STATE_FILE=/var/lib/ananke/update-last.env
|
||||||
|
Environment=ANANKE_UPDATE_ALLOW_QUALITY_FALLBACK=1
|
||||||
ExecStart=/usr/local/lib/ananke/ananke-self-update.sh
|
ExecStart=/usr/local/lib/ananke/ananke-self-update.sh
|
||||||
TimeoutStartSec=1800
|
TimeoutStartSec=1800
|
||||||
|
StandardOutput=journal
|
||||||
|
StandardError=journal
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=120
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
|||||||
@ -10,6 +10,60 @@ REPO_URL="${ANANKE_REPO_URL:-ssh://git@scm.bstein.dev:2242/bstein/ananke.git}"
|
|||||||
BRANCH="${ANANKE_REPO_BRANCH:-main}"
|
BRANCH="${ANANKE_REPO_BRANCH:-main}"
|
||||||
REPO_DIR="${ANANKE_REPO_DIR:-/opt/ananke}"
|
REPO_DIR="${ANANKE_REPO_DIR:-/opt/ananke}"
|
||||||
HOST_SHORT="$(hostname -s 2>/dev/null || hostname)"
|
HOST_SHORT="$(hostname -s 2>/dev/null || hostname)"
|
||||||
|
LOG_FILE="${ANANKE_UPDATE_LOG_FILE:-/var/log/ananke/update.log}"
|
||||||
|
STATE_FILE="${ANANKE_UPDATE_STATE_FILE:-/var/lib/ananke/update-last.env}"
|
||||||
|
LOCK_FILE="${ANANKE_UPDATE_LOCK_FILE:-/var/lock/ananke-update.lock}"
|
||||||
|
ALLOW_QUALITY_FALLBACK="${ANANKE_UPDATE_ALLOW_QUALITY_FALLBACK:-1}"
|
||||||
|
QUALITY_GATE_MODE="${ANANKE_ENFORCE_QUALITY_GATE:-1}"
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "${LOG_FILE}")" "$(dirname "${STATE_FILE}")" "$(dirname "${LOCK_FILE}")"
|
||||||
|
touch "${LOG_FILE}" "${STATE_FILE}"
|
||||||
|
chmod 0644 "${LOG_FILE}" "${STATE_FILE}" || true
|
||||||
|
|
||||||
|
exec 9>"${LOCK_FILE}"
|
||||||
|
if ! flock -n 9; then
|
||||||
|
printf '[self-update] %s another update is already running; exiting\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" | tee -a "${LOG_FILE}"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec > >(tee -a "${LOG_FILE}") 2>&1
|
||||||
|
|
||||||
|
write_state() {
|
||||||
|
local status="$1"
|
||||||
|
local detail="$2"
|
||||||
|
local from_rev="$3"
|
||||||
|
local to_rev="$4"
|
||||||
|
local now
|
||||||
|
now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
||||||
|
cat > "${STATE_FILE}" <<EOF
|
||||||
|
timestamp=${now}
|
||||||
|
host=${HOST_SHORT}
|
||||||
|
status=${status}
|
||||||
|
detail=${detail}
|
||||||
|
from_rev=${from_rev}
|
||||||
|
to_rev=${to_rev}
|
||||||
|
branch=${BRANCH}
|
||||||
|
repo=${REPO_URL}
|
||||||
|
EOF
|
||||||
|
chmod 0644 "${STATE_FILE}" || true
|
||||||
|
}
|
||||||
|
|
||||||
|
on_error() {
|
||||||
|
local line="$1"
|
||||||
|
local cmd="$2"
|
||||||
|
local code="$3"
|
||||||
|
local from_rev="${4:-unknown}"
|
||||||
|
local to_rev="${5:-unknown}"
|
||||||
|
echo "[self-update] failure rc=${code} line=${line} cmd=${cmd}"
|
||||||
|
write_state "failed" "rc=${code};line=${line};cmd=${cmd}" "${from_rev}" "${to_rev}"
|
||||||
|
exit "${code}"
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENT_FROM_REV="unknown"
|
||||||
|
TARGET_TO_REV="unknown"
|
||||||
|
trap 'on_error "${LINENO}" "${BASH_COMMAND}" "$?" "${CURRENT_FROM_REV}" "${TARGET_TO_REV}"' ERR
|
||||||
|
|
||||||
|
echo "[self-update] started host=${HOST_SHORT} branch=${BRANCH} repo=${REPO_URL}"
|
||||||
|
|
||||||
mkdir -p "$(dirname "${REPO_DIR}")"
|
mkdir -p "$(dirname "${REPO_DIR}")"
|
||||||
if [[ ! -d "${REPO_DIR}/.git" ]]; then
|
if [[ ! -d "${REPO_DIR}/.git" ]]; then
|
||||||
@ -18,10 +72,18 @@ if [[ ! -d "${REPO_DIR}/.git" ]]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cd "${REPO_DIR}"
|
cd "${REPO_DIR}"
|
||||||
|
git config --global --add safe.directory "${REPO_DIR}" || true
|
||||||
|
CURRENT_FROM_REV="$(git rev-parse --short HEAD 2>/dev/null || echo unknown)"
|
||||||
echo "[self-update] syncing ${BRANCH}"
|
echo "[self-update] syncing ${BRANCH}"
|
||||||
git fetch origin --prune
|
git fetch origin --prune
|
||||||
git checkout "${BRANCH}"
|
git checkout "${BRANCH}"
|
||||||
|
TARGET_TO_REV="$(git rev-parse --short "origin/${BRANCH}" 2>/dev/null || echo unknown)"
|
||||||
git reset --hard "origin/${BRANCH}"
|
git reset --hard "origin/${BRANCH}"
|
||||||
|
if [[ "${CURRENT_FROM_REV}" == "${TARGET_TO_REV}" ]]; then
|
||||||
|
echo "[self-update] already up to date at ${CURRENT_FROM_REV}"
|
||||||
|
else
|
||||||
|
echo "[self-update] update candidate ${CURRENT_FROM_REV} -> ${TARGET_TO_REV}"
|
||||||
|
fi
|
||||||
|
|
||||||
echo "[self-update] running installer"
|
echo "[self-update] running installer"
|
||||||
# Keep host configs aligned with tracked templates so startup/shutdown drills
|
# Keep host configs aligned with tracked templates so startup/shutdown drills
|
||||||
@ -36,4 +98,18 @@ if [[ -z "${ANANKE_FORCE_CONFIG_TEMPLATE:-}" ]]; then
|
|||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
"${REPO_DIR}/scripts/install.sh"
|
export ANANKE_ENFORCE_QUALITY_GATE="${QUALITY_GATE_MODE}"
|
||||||
|
if "${REPO_DIR}/scripts/install.sh"; then
|
||||||
|
write_state "ok" "install-success" "${CURRENT_FROM_REV}" "${TARGET_TO_REV}"
|
||||||
|
echo "[self-update] completed successfully"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "${ALLOW_QUALITY_FALLBACK}" == "1" || "${ALLOW_QUALITY_FALLBACK}" == "true" ]]; then
|
||||||
|
echo "[self-update] install failed in strict mode; retrying once with ANANKE_ENFORCE_QUALITY_GATE=0"
|
||||||
|
export ANANKE_ENFORCE_QUALITY_GATE=0
|
||||||
|
"${REPO_DIR}/scripts/install.sh"
|
||||||
|
write_state "degraded-ok" "fallback-no-quality-gate" "${CURRENT_FROM_REV}" "${TARGET_TO_REV}"
|
||||||
|
echo "[self-update] completed via fallback mode"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user