文件
hyb-oa/deploy/trialrun/install-warch3-ops-timer.sh
T
wangsli 325c592aba
ci-e2e / e2e (push) Waiting to run
ci-minimal / check-minimal (push) Waiting to run
加固生产运维定时器绑定(07-26-internal-ops-recovery-baseline)
2026-07-27 07:59:48 +08:00

157 行
5.2 KiB
Bash

#!/usr/bin/env bash
set -euo pipefail
REMOTE_DIR="${REMOTE_DIR:-/opt/hyb-oa-trialrun}"
REMOTE_ENV_FILE="${REMOTE_ENV_FILE:-${REMOTE_DIR}/deploy/trialrun/.env}"
COMPOSE_FILE="${COMPOSE_FILE:-deploy/trialrun/docker-compose.yml}"
COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:-hyb-oa-trialrun}"
POSTGRES_DATA_DIR="${POSTGRES_DATA_DIR:-}"
STORAGE_HOST_DIR="${STORAGE_HOST_DIR:-}"
BUILD_SHA="${BUILD_SHA:-}"
VITE_BUILD_SHA="${VITE_BUILD_SHA:-}"
SERVICE_NAME="${SERVICE_NAME:-hyb-oa-warch3-ops}"
RUN_AT="${RUN_AT:-07:30}"
MODE="${1:-install}"
SERVICE_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
TIMER_FILE="/etc/systemd/system/${SERVICE_NAME}.timer"
need_root() {
if [[ "$(id -u)" != "0" ]]; then
echo "[ERROR] 请以 root 执行,或使用 sudo" >&2
exit 1
fi
}
validate_data_path() {
local name="$1"
local value="$2"
if [[ -z "$value" || "$value" != /* || ! "$value" =~ ^/[A-Za-z0-9._/-]+$ ]]; then
echo "[ERROR] $name 必须显式提供受限字符集的绝对路径" >&2
exit 1
fi
if [[ "$value" == "/" || "$value" == */ || "$value" == *"//"* \
|| "/$value/" == *"/../"* || "/$value/" == *"/./"* ]]; then
echo "[ERROR] $name 不得是根目录、尾随斜杠或包含空、.、.. 路径段" >&2
exit 1
fi
}
uninstall_timer() {
need_root
systemctl disable --now "${SERVICE_NAME}.timer" >/dev/null 2>&1 || true
systemctl stop "${SERVICE_NAME}.service" >/dev/null 2>&1 || true
rm -f "$SERVICE_FILE" "$TIMER_FILE"
systemctl daemon-reload
echo "[warch3-ops-timer] uninstalled ${SERVICE_NAME}"
}
install_timer() {
need_root
if [[ ! -d "$REMOTE_DIR" ]]; then
echo "[ERROR] REMOTE_DIR 不存在: $REMOTE_DIR" >&2
exit 1
fi
if [[ ! -f "$REMOTE_ENV_FILE" ]]; then
echo "[ERROR] 远端 env 不存在: $REMOTE_ENV_FILE" >&2
exit 1
fi
if [[ ! "$COMPOSE_PROJECT_NAME" =~ ^[a-z0-9][a-z0-9_-]*$ ]]; then
echo "[ERROR] COMPOSE_PROJECT_NAME 格式无效" >&2
exit 1
fi
validate_data_path POSTGRES_DATA_DIR "$POSTGRES_DATA_DIR"
validate_data_path STORAGE_HOST_DIR "$STORAGE_HOST_DIR"
if [[ "$POSTGRES_DATA_DIR" == "$STORAGE_HOST_DIR" \
|| "$POSTGRES_DATA_DIR" == "$STORAGE_HOST_DIR"/* \
|| "$STORAGE_HOST_DIR" == "$POSTGRES_DATA_DIR"/* ]]; then
echo "[ERROR] PostgreSQL 与附件宿主目录必须相互独立" >&2
exit 1
fi
if [[ ! -f "$POSTGRES_DATA_DIR/PG_VERSION" ]]; then
echo "[ERROR] POSTGRES_DATA_DIR 必须是包含 PG_VERSION 的现存 PGDATA" >&2
exit 1
fi
if [[ ! -d "$STORAGE_HOST_DIR" ]]; then
echo "[ERROR] STORAGE_HOST_DIR 必须是现存目录" >&2
exit 1
fi
if [[ ! "$BUILD_SHA" =~ ^[0-9a-fA-F]{40,64}$ ]]; then
echo "[ERROR] BUILD_SHA 必须是 40-64 位十六进制完整提交标识" >&2
exit 1
fi
BUILD_SHA="${BUILD_SHA,,}"
VITE_BUILD_SHA="${VITE_BUILD_SHA,,}"
if [[ ! "$VITE_BUILD_SHA" =~ ^[0-9a-f]{12}$ || "${BUILD_SHA:0:12}" != "$VITE_BUILD_SHA" ]]; then
echo "[ERROR] VITE_BUILD_SHA 必须是 BUILD_SHA 的 12 位十六进制前缀" >&2
exit 1
fi
local compose_exec
if docker compose version >/dev/null 2>&1; then
compose_exec="docker compose"
elif command -v docker-compose >/dev/null 2>&1; then
compose_exec="docker-compose"
else
echo "[ERROR] 远端既没有 docker compose,也没有 docker-compose" >&2
exit 1
fi
cat >"$SERVICE_FILE" <<SERVICE
[Unit]
Description=hyb-oa WARCH3 archive stabilization ops daily check
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
WorkingDirectory=${REMOTE_DIR}
Environment=REMOTE_DIR=${REMOTE_DIR}
Environment=REMOTE_ENV_FILE=${REMOTE_ENV_FILE}
Environment=COMPOSE_FILE=${COMPOSE_FILE}
Environment=COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME}
Environment=POSTGRES_DATA_DIR=${POSTGRES_DATA_DIR}
Environment=STORAGE_HOST_DIR=${STORAGE_HOST_DIR}
Environment=BUILD_SHA=${BUILD_SHA}
Environment=VITE_BUILD_SHA=${VITE_BUILD_SHA}
Environment=LIVE_SMOKE_BASE_URL=https://oa.hyinda.com
Environment=WARCH3_SEND_ALERT=1
Environment=WARCH3_OPS_ALERT_SEND=1
ExecStart=/bin/bash -lc 'cd "$REMOTE_DIR" && ${compose_exec} -p "$COMPOSE_PROJECT_NAME" -f "$COMPOSE_FILE" --env-file "$REMOTE_ENV_FILE" exec -T server sh -lc "cd /app && LIVE_SMOKE_BASE_URL=https://oa.hyinda.com WARCH3_SEND_ALERT=1 WARCH3_OPS_ALERT_SEND=1 bash scripts/qa/run-warch3-ops-daily.sh"'
SERVICE
cat >"$TIMER_FILE" <<TIMER
[Unit]
Description=Run hyb-oa WARCH3 archive stabilization ops daily
[Timer]
OnCalendar=*-*-* ${RUN_AT}:00
Persistent=true
Unit=${SERVICE_NAME}.service
[Install]
WantedBy=timers.target
TIMER
systemctl daemon-reload
systemctl enable --now "${SERVICE_NAME}.timer"
systemctl list-timers "${SERVICE_NAME}.timer" --no-pager
echo "[warch3-ops-timer] installed ${SERVICE_NAME}.timer at ${RUN_AT} local server time (Asia/Shanghai expected)"
}
case "$MODE" in
install|"")
install_timer
;;
--uninstall|uninstall)
uninstall_timer
;;
--help|-h)
echo "Usage: REMOTE_DIR=/opt/hyb-oa-trialrun COMPOSE_PROJECT_NAME=<project> POSTGRES_DATA_DIR=<absolute-pgdata> STORAGE_HOST_DIR=<absolute-storage> BUILD_SHA=<full-sha> VITE_BUILD_SHA=<12-char-prefix> bash deploy/trialrun/install-warch3-ops-timer.sh [install|uninstall]"
;;
*)
echo "[ERROR] unsupported mode: $MODE" >&2
exit 2
;;
esac