159 行
6.0 KiB
Bash
可执行文件
159 行
6.0 KiB
Bash
可执行文件
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
READY_URL="${READY_URL:-https://oa.hyinda.com/ready}"
|
|
PROBE_SOURCE="${PROBE_SOURCE:-}"
|
|
PROBE_TARGET="${PROBE_TARGET:-/usr/local/sbin/hyb-oa-public-app-health}"
|
|
ALERT_WEBHOOK_FILE="${ALERT_WEBHOOK_FILE:-}"
|
|
ALERT_HELPER_SOURCE="${ALERT_HELPER_SOURCE:-}"
|
|
ALERT_HELPER_TARGET="${ALERT_HELPER_TARGET:-/usr/local/sbin/hyb-oa-wecom-group-alert}"
|
|
STATE_DIR="${STATE_DIR:-/var/lib/hyb-oa-app-health}"
|
|
FAILURE_THRESHOLD="${FAILURE_THRESHOLD:-2}"
|
|
TIMEOUT_SECONDS="${TIMEOUT_SECONDS:-10}"
|
|
SERVICE_NAME="${SERVICE_NAME:-hyb-oa-public-app-health}"
|
|
SYSTEMD_DIR="${SYSTEMD_DIR:-/etc/systemd/system}"
|
|
MODE="${1:-install}"
|
|
|
|
fail() {
|
|
echo "[app-health-installer][ERROR] $1" >&2
|
|
exit 1
|
|
}
|
|
|
|
need_root() {
|
|
[[ "$(id -u)" == "0" ]] || fail "root privileges are required"
|
|
}
|
|
|
|
validate_absolute_path() {
|
|
local name="$1"
|
|
local value="$2"
|
|
if [[ -z "$value" || "$value" != /* || ! "$value" =~ ^/[A-Za-z0-9._/-]+$ ]]; then
|
|
fail "$name must be an explicit safe absolute path"
|
|
fi
|
|
if [[ "$value" == "/" || "$value" == */ || "$value" == *"//"* \
|
|
|| "/$value/" == *"/../"* || "/$value/" == *"/./"* ]]; then
|
|
fail "$name contains an unsafe path segment"
|
|
fi
|
|
}
|
|
|
|
validate_managed_targets() {
|
|
[[ "$PROBE_TARGET" == "/usr/local/sbin/hyb-oa-public-app-health" ]] \
|
|
|| fail "PROBE_TARGET must remain /usr/local/sbin/hyb-oa-public-app-health"
|
|
[[ "$ALERT_HELPER_TARGET" == "/usr/local/sbin/hyb-oa-wecom-group-alert" ]] \
|
|
|| fail "ALERT_HELPER_TARGET must remain /usr/local/sbin/hyb-oa-wecom-group-alert"
|
|
[[ "$STATE_DIR" == "/var/lib/hyb-oa-app-health" ]] \
|
|
|| fail "STATE_DIR must remain /var/lib/hyb-oa-app-health"
|
|
[[ "$SYSTEMD_DIR" == "/etc/systemd/system" ]] \
|
|
|| fail "SYSTEMD_DIR must remain /etc/systemd/system"
|
|
[[ "$SERVICE_NAME" == "hyb-oa-public-app-health" ]] \
|
|
|| fail "SERVICE_NAME must remain hyb-oa-public-app-health"
|
|
}
|
|
|
|
validate_inputs() {
|
|
local name value
|
|
for name in PROBE_SOURCE PROBE_TARGET ALERT_WEBHOOK_FILE ALERT_HELPER_SOURCE ALERT_HELPER_TARGET STATE_DIR SYSTEMD_DIR; do
|
|
value="${!name:-}"
|
|
validate_absolute_path "$name" "$value"
|
|
done
|
|
validate_managed_targets
|
|
[[ "$READY_URL" =~ ^https://[A-Za-z0-9.-]+(:([0-9]{1,5}))?/ready$ ]] \
|
|
|| fail "READY_URL must be an HTTPS /ready endpoint without query or fragment"
|
|
if [[ -n "${BASH_REMATCH[2]:-}" && ("${BASH_REMATCH[2]}" -lt 1 || "${BASH_REMATCH[2]}" -gt 65535) ]]; then
|
|
fail "READY_URL port is invalid"
|
|
fi
|
|
[[ "$FAILURE_THRESHOLD" == "2" ]] || fail "FAILURE_THRESHOLD must remain 2"
|
|
[[ "$TIMEOUT_SECONDS" =~ ^([1-9]|[12][0-9]|30)$ ]] || fail "TIMEOUT_SECONDS must be between 1 and 30"
|
|
[[ -f "$PROBE_SOURCE" && ! -L "$PROBE_SOURCE" ]] || fail "probe source is missing"
|
|
[[ -f "$ALERT_HELPER_SOURCE" && ! -L "$ALERT_HELPER_SOURCE" ]] || fail "alert helper source is missing"
|
|
[[ -f "$ALERT_WEBHOOK_FILE" && ! -L "$ALERT_WEBHOOK_FILE" \
|
|
&& "$(stat -c %a "$ALERT_WEBHOOK_FILE")" == "600" \
|
|
&& "$(stat -c %u "$ALERT_WEBHOOK_FILE")" == "0" ]] \
|
|
|| fail "alert webhook file must be root-owned with mode 0600"
|
|
[[ -d "$SYSTEMD_DIR" && ! -L "$SYSTEMD_DIR" ]] || fail "systemd directory is invalid"
|
|
command -v python3 >/dev/null 2>&1 || fail "python3 is required"
|
|
command -v systemctl >/dev/null 2>&1 || fail "systemctl is required"
|
|
}
|
|
|
|
install_monitor() {
|
|
need_root
|
|
validate_inputs
|
|
systemctl disable --now "${SERVICE_NAME}.timer" >/dev/null 2>&1 || true
|
|
systemctl stop "${SERVICE_NAME}.service" >/dev/null 2>&1 || true
|
|
install -o root -g root -m 0755 "$PROBE_SOURCE" "$PROBE_TARGET"
|
|
install -o root -g root -m 0755 "$ALERT_HELPER_SOURCE" "$ALERT_HELPER_TARGET"
|
|
mkdir -p "$STATE_DIR"
|
|
[[ -d "$STATE_DIR" && ! -L "$STATE_DIR" ]] || fail "state directory is invalid"
|
|
chown root:root "$STATE_DIR"
|
|
chmod 0700 "$STATE_DIR"
|
|
|
|
cat >"$SYSTEMD_DIR/${SERVICE_NAME}.service" <<SERVICE
|
|
[Unit]
|
|
Description=hyb-oa independent public application readiness probe
|
|
After=network-online.target
|
|
Wants=network-online.target
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
UMask=0077
|
|
ExecStart=/usr/bin/python3 ${PROBE_TARGET} --ready-url ${READY_URL} --state-dir ${STATE_DIR} --webhook-file ${ALERT_WEBHOOK_FILE} --alert-helper ${ALERT_HELPER_TARGET} --failure-threshold ${FAILURE_THRESHOLD} --timeout-seconds ${TIMEOUT_SECONDS}
|
|
TimeoutStartSec=30
|
|
SERVICE
|
|
|
|
cat >"$SYSTEMD_DIR/${SERVICE_NAME}.timer" <<TIMER
|
|
[Unit]
|
|
Description=Check hyb-oa public application readiness every five minutes
|
|
|
|
[Timer]
|
|
OnCalendar=*:0/5
|
|
Persistent=true
|
|
AccuracySec=10s
|
|
Unit=${SERVICE_NAME}.service
|
|
|
|
[Install]
|
|
WantedBy=timers.target
|
|
TIMER
|
|
chmod 0644 "$SYSTEMD_DIR/${SERVICE_NAME}.service" "$SYSTEMD_DIR/${SERVICE_NAME}.timer"
|
|
systemctl daemon-reload
|
|
echo "[app-health-installer][PASS] disabled application health monitor installed"
|
|
}
|
|
|
|
enable_monitor() {
|
|
install_monitor
|
|
systemctl enable --now "${SERVICE_NAME}.timer"
|
|
echo "[app-health-installer][PASS] application health timer enabled"
|
|
}
|
|
|
|
uninstall_monitor() {
|
|
need_root
|
|
validate_absolute_path PROBE_TARGET "$PROBE_TARGET"
|
|
validate_absolute_path SYSTEMD_DIR "$SYSTEMD_DIR"
|
|
[[ "$PROBE_TARGET" == "/usr/local/sbin/hyb-oa-public-app-health" ]] \
|
|
|| fail "PROBE_TARGET must remain /usr/local/sbin/hyb-oa-public-app-health"
|
|
[[ "$SYSTEMD_DIR" == "/etc/systemd/system" ]] \
|
|
|| fail "SYSTEMD_DIR must remain /etc/systemd/system"
|
|
[[ "$SERVICE_NAME" == "hyb-oa-public-app-health" ]] \
|
|
|| fail "SERVICE_NAME must remain hyb-oa-public-app-health"
|
|
systemctl disable --now "${SERVICE_NAME}.timer" >/dev/null 2>&1 || true
|
|
systemctl stop "${SERVICE_NAME}.service" >/dev/null 2>&1 || true
|
|
rm -f -- "$SYSTEMD_DIR/${SERVICE_NAME}.timer" "$SYSTEMD_DIR/${SERVICE_NAME}.service" "$PROBE_TARGET"
|
|
systemctl daemon-reload
|
|
echo "[app-health-installer][PASS] monitor removed; state and shared alert files retained"
|
|
}
|
|
|
|
case "$MODE" in
|
|
install)
|
|
install_monitor
|
|
;;
|
|
enable)
|
|
enable_monitor
|
|
;;
|
|
uninstall|--uninstall)
|
|
uninstall_monitor
|
|
;;
|
|
--help|-h)
|
|
echo "Usage: <explicit probe/webhook/helper paths> bash install-offhost-app-health-monitor.sh [install|enable|uninstall]"
|
|
;;
|
|
*)
|
|
fail "unsupported mode"
|
|
;;
|
|
esac
|