Files
awoooi/scripts/reboot-recovery/install-full-host-reboot-orchestrator.sh
ogt 4481f18aa1
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 2m20s
CD Pipeline / post-deploy-checks (push) Has been cancelled
CD Pipeline / build-and-deploy (push) Has been cancelled
feat(reboot): add ai log triage auto recovery
2026-07-09 16:22:21 +08:00

149 lines
5.0 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)"
UNIT_NAME="awoooi-full-host-reboot-orchestrator"
SYSTEMD_DIR="${SYSTEMD_DIR:-/etc/systemd/system}"
ENV_DIR="${ENV_DIR:-/etc/awoooi}"
LOG_DIR="${LOG_DIR:-/var/log/awoooi/reboot-recovery}"
INSTALL_ROOT="${INSTALL_ROOT:-/opt/awoooi/reboot-recovery}"
MODE="dry-run"
ENABLE_NOW=0
usage() {
cat <<'USAGE'
Usage: install-full-host-reboot-orchestrator.sh [--dry-run|--apply|--verify-only|--rollback] [--enable-now]
Installs the AWOOOI full-host reboot recovery orchestrator source and systemd
units. The default is --dry-run. Runtime scheduling requires both --apply and
--enable-now so a source deploy cannot accidentally start host automation.
Options:
--dry-run Print the install plan only. This is the default.
--apply Stage source files and systemd units, then daemon-reload.
--verify-only Read back systemd timer/service/source status without writing.
--rollback Disable and remove only this orchestrator unit/timer.
--enable-now With --apply, enable and start only the orchestrator timer.
-h, --help Show this help.
Forbidden here: reboot, node drain, firewall changes, DB restore/drop/truncate,
Docker prune, secret/session/.env/raw-volume reads, repo/ref destructive ops.
USAGE
}
while [[ $# -gt 0 ]]; do
case "$1" in
--dry-run)
MODE="dry-run"
;;
--apply)
MODE="apply"
;;
--verify-only)
MODE="verify"
;;
--rollback)
MODE="rollback"
;;
--enable-now)
ENABLE_NOW=1
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 2
;;
esac
shift
done
cat <<PLAN
AWOOOI_FULL_HOST_REBOOT_ORCHESTRATOR_INSTALL_PLAN=1
mode=${MODE}
enable_now=${ENABLE_NOW}
install_root=${INSTALL_ROOT}
systemd_dir=${SYSTEMD_DIR}
env_dir=${ENV_DIR}
log_dir=${LOG_DIR}
source_root=${ROOT_DIR}
unit=${UNIT_NAME}
apply_command=bash scripts/reboot-recovery/install-full-host-reboot-orchestrator.sh --apply
enable_command=bash scripts/reboot-recovery/install-full-host-reboot-orchestrator.sh --apply --enable-now
verify_command=bash scripts/reboot-recovery/install-full-host-reboot-orchestrator.sh --verify-only
rollback_command=bash scripts/reboot-recovery/install-full-host-reboot-orchestrator.sh --rollback
PLAN
verify_status() {
cat <<STATUS
FULL_HOST_ORCHESTRATOR_TIMER_ENABLED=$(systemctl is-enabled "${UNIT_NAME}.timer" 2>/dev/null || true)
FULL_HOST_ORCHESTRATOR_TIMER_ACTIVE=$(systemctl is-active "${UNIT_NAME}.timer" 2>/dev/null || true)
FULL_HOST_ORCHESTRATOR_SERVICE_LOAD=$(systemctl show "${UNIT_NAME}.service" -p LoadState --value 2>/dev/null || true)
FULL_HOST_ORCHESTRATOR_SERVICE_RESULT=$(systemctl show "${UNIT_NAME}.service" -p Result --value 2>/dev/null || true)
FULL_HOST_ORCHESTRATOR_SERVICE_LAST_STATUS=$(systemctl show "${UNIT_NAME}.service" -p ExecMainStatus --value 2>/dev/null || true)
FULL_HOST_ORCHESTRATOR_INSTALL_ROOT_PRESENT=$([ -x "${INSTALL_ROOT}/scripts/reboot-recovery/full-host-reboot-orchestrator.sh" ] && echo 1 || echo 0)
FULL_HOST_ORCHESTRATOR_AI_TRIAGE_PRESENT=$([ -x "${INSTALL_ROOT}/scripts/reboot-recovery/ai-log-triage-auto-recovery.sh" ] && echo 1 || echo 0)
FULL_HOST_ORCHESTRATOR_LATEST_ARTIFACT_DIR=$(find "$LOG_DIR" -maxdepth 1 -type d -name '20*' 2>/dev/null | sort | tail -n 1 || true)
STATUS
}
if [[ "$MODE" != "apply" ]]; then
case "$MODE" in
dry-run)
echo "DRY_RUN=1"
exit 0
;;
verify)
verify_status
exit 0
;;
rollback)
systemctl disable --now "${UNIT_NAME}.timer" >/dev/null 2>&1 || true
systemctl stop "${UNIT_NAME}.service" >/dev/null 2>&1 || true
rm -f "${SYSTEMD_DIR}/${UNIT_NAME}.timer" "${SYSTEMD_DIR}/${UNIT_NAME}.service"
systemctl daemon-reload
echo "FULL_HOST_ORCHESTRATOR_ROLLBACK_DONE=1"
verify_status
exit 0
;;
*)
printf 'Unsupported mode: %s\n' "$MODE" >&2
exit 2
;;
esac
fi
install -d "$SYSTEMD_DIR" "$ENV_DIR" "$LOG_DIR" "$INSTALL_ROOT"
rsync -a \
--exclude '.git' \
--exclude '__pycache__' \
--exclude '.pytest_cache' \
"${ROOT_DIR}/" "${INSTALL_ROOT}/"
install -m 0644 "${SCRIPT_DIR}/${UNIT_NAME}.service" "${SYSTEMD_DIR}/${UNIT_NAME}.service"
install -m 0644 "${SCRIPT_DIR}/${UNIT_NAME}.timer" "${SYSTEMD_DIR}/${UNIT_NAME}.timer"
if [[ ! -f "${ENV_DIR}/reboot-recovery.env" ]]; then
install -m 0600 /dev/null "${ENV_DIR}/reboot-recovery.env"
cat >"${ENV_DIR}/reboot-recovery.env" <<'ENV'
# Optional no-secret runtime knobs for full-host reboot recovery.
# Do not place raw tokens in source control. Put host-local secrets only in this root-owned file.
HOSTS="99 110 111 112 120 121 188"
RECOVERY_SLO_SECONDS=600
SSH_TIMEOUT_SECONDS=12
DISABLE_TELEGRAM=1
# TELEGRAM_NOTIFY_SCRIPT=/usr/local/sbin/awoooi-telegram-notify
ENV
fi
systemctl daemon-reload
if [[ "$ENABLE_NOW" -eq 1 ]]; then
systemctl enable --now "${UNIT_NAME}.timer"
else
echo "ENABLE_NOW_SKIPPED=1"
fi
verify_status