#!/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" <"$SYSTEMD_DIR/${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: bash install-offhost-app-health-monitor.sh [install|enable|uninstall]" ;; *) fail "unsupported mode" ;; esac