- Ansible: 部署时自动配置 CoreDNS forward 为 IPv4,避免 ACME 解析失败 - 01-01/01-07: 文档增加 CoreDNS 设置说明 - 03-03: Tomcat webapps.dist 复制、HTTP/HTTPS 双 Ingress、显式 Dashboard IngressRoute - traefik-dashboard-acme: tomcat-acme.yaml、404 排查说明 - HAProxy: 健康检查与 PROXY 配置拆分,18080/18443 部署与验证脚本 Made-with: Cursor
212 lines
8.3 KiB
Bash
212 lines
8.3 KiB
Bash
#!/usr/bin/env bash
|
||
# HAProxy 配置与后端验证(OpenWrt 18080/18443,第三方 onecloud curl)
|
||
# 核心:ansible/files/01-08-haproxy/*.cfg 语法正确;可选经 curl 验证运行时与后端
|
||
set -euo pipefail
|
||
|
||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||
CFG_DIR="${ROOT_DIR}/ansible/files/01-08-haproxy"
|
||
MATRIX_FILE="${ROOT_DIR}/docs/00-02-验证矩阵.md"
|
||
SSH_OPENWRT="${SSH_OPENWRT:-openwrt}"
|
||
VERIFY_HOST="${VERIFY_HOST:-onecloud}"
|
||
OPENWRT_IP="${OPENWRT_IP:-192.168.2.1}"
|
||
HTTP_PORT="${HTTP_PORT:-18080}"
|
||
HTTPS_PORT="${HTTPS_PORT:-18443}"
|
||
DEPLOY_MATRIX="${DEPLOY_MATRIX:-none}"
|
||
HTTPS_HOSTS="" # 逗号分隔,如 test01.jackadam.top,test02.jackadam.top
|
||
UPDATE_MATRIX=1
|
||
CFG_ONLY=0 # 仅 haproxy -c 校验本目录 cfg,不跑 curl
|
||
|
||
usage() {
|
||
cat <<'EOF'
|
||
用法:
|
||
./scripts/01-08-verify-haproxy.sh [选项]
|
||
|
||
选项:
|
||
--cfg-only 仅校验 ansible/files/01-08-haproxy/*.cfg 语法(OpenWrt 上 haproxy -c),不跑 curl
|
||
--deploy-matrix <none|http|tls> 验证前一键部署矩阵(默认 none)
|
||
--verify-host <name> curl 执行主机,SSH 目标(默认 onecloud)
|
||
--openwrt-ip <ip> OpenWrt/网关 IP(默认 192.168.2.1)
|
||
--http-port <port> HAProxy HTTP 端口(默认 18080)
|
||
--https-port <port> HAProxy HTTPS 端口(默认 18443)
|
||
--https-hosts <domain1,domain2> HTTPS 校验域名,M1~M4 对应(缺省时不校验 HTTPS)
|
||
--update-matrix 验证通过后更新验证矩阵(默认启用)
|
||
--no-update-matrix 不更新验证矩阵
|
||
-h, --help 显示帮助
|
||
|
||
前置:ssh openwrt 可用;完整验证还需 ssh onecloud;OpenWrt HAProxy 已按 18080/18443 配置(运行时验证)
|
||
EOF
|
||
}
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
--cfg-only) CFG_ONLY=1; shift ;;
|
||
--deploy-matrix) DEPLOY_MATRIX="${2:-none}"; shift 2 ;;
|
||
--verify-host) VERIFY_HOST="${2:-onecloud}"; shift 2 ;;
|
||
--openwrt-ip) OPENWRT_IP="${2:-192.168.2.1}"; shift 2 ;;
|
||
--http-port) HTTP_PORT="${2:-18080}"; shift 2 ;;
|
||
--https-port) HTTPS_PORT="${2:-18443}"; shift 2 ;;
|
||
--https-hosts) HTTPS_HOSTS="${2:-}"; shift 2 ;;
|
||
--update-matrix) UPDATE_MATRIX=1; shift ;;
|
||
--no-update-matrix) UPDATE_MATRIX=0; shift ;;
|
||
-h|--help) usage; exit 0 ;;
|
||
*) echo "[ERR] 未知参数: $1"; usage; exit 1 ;;
|
||
esac
|
||
done
|
||
|
||
REMOTE_DIR="/tmp/haproxy-verify"
|
||
|
||
if [[ $CFG_ONLY -eq 1 ]]; then
|
||
echo "=== HAProxy cfg 语法校验(${SSH_OPENWRT},ansible/files/01-08-haproxy/*.cfg)==="
|
||
else
|
||
echo "=== HAProxy 验证(${SSH_OPENWRT} → ${VERIFY_HOST} curl ${OPENWRT_IP}:${HTTP_PORT}/${HTTPS_PORT})==="
|
||
fi
|
||
|
||
# 0. 按需部署矩阵(--cfg-only 时不部署)
|
||
if [[ $CFG_ONLY -eq 1 ]]; then
|
||
:
|
||
elif [[ "$DEPLOY_MATRIX" == "http" ]]; then
|
||
echo "[0] 部署 02-05 nginx 矩阵(http)..."
|
||
(cd "$ROOT_DIR" && ansible-playbook -i ansible/inventory.ini ansible/playbooks/nginx-matrix-deploy.yml) || { echo "[ERR] nginx-matrix-deploy 失败" >&2; exit 1; }
|
||
echo " [OK] HTTP 矩阵已部署"
|
||
elif [[ "$DEPLOY_MATRIX" == "tls" ]]; then
|
||
echo "[0] 部署 nginx 矩阵 TLS 版..."
|
||
(cd "$ROOT_DIR" && ansible-playbook -i ansible/inventory.ini ansible/playbooks/nginx-matrix-tls-deploy.yml) || { echo "[ERR] nginx-matrix-tls-deploy 失败" >&2; exit 1; }
|
||
echo " [OK] TLS 矩阵已部署"
|
||
[[ -z "$HTTPS_HOSTS" ]] && HTTPS_HOSTS="test01.jackadam.top,test02.jackadam.top,test03.jackadam.top,test04.jackadam.top"
|
||
fi
|
||
|
||
if [[ ! -d "$CFG_DIR" ]]; then
|
||
echo "[ERR] cfg 目录不存在: $CFG_DIR" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# 1. 拷贝 cfg 到 OpenWrt(-O 强制旧 SCP 协议,兼容无 sftp-server 的 OpenWrt)
|
||
echo "[1/4] 拷贝 cfg 到 ${SSH_OPENWRT}:${REMOTE_DIR}..."
|
||
ssh "$SSH_OPENWRT" "mkdir -p ${REMOTE_DIR}"
|
||
scp -q -O "${CFG_DIR}"/*.cfg "${SSH_OPENWRT}:${REMOTE_DIR}/" 2>/dev/null || {
|
||
echo " [INFO] scp -O 不可用,改用 ssh 管道传输..."
|
||
for f in "${CFG_DIR}"/*.cfg; do
|
||
bn=$(basename "$f")
|
||
ssh "$SSH_OPENWRT" "cat > ${REMOTE_DIR}/${bn}" < "$f"
|
||
done
|
||
}
|
||
|
||
# 2. 语法校验
|
||
echo "[2/4] 校验 cfg 语法..."
|
||
SYNTAX_FAIL=0
|
||
for cfg in haproxy-no-check haproxy-http haproxy-tls haproxy-proxy-http-tls; do
|
||
if ssh "$SSH_OPENWRT" "haproxy -c -f ${REMOTE_DIR}/${cfg}.cfg" 2>/dev/null; then
|
||
echo " [OK] ${cfg}.cfg"
|
||
else
|
||
echo " [FAIL] ${cfg}.cfg" >&2
|
||
SYNTAX_FAIL=1
|
||
fi
|
||
done
|
||
if ssh "$SSH_OPENWRT" "haproxy -c -f ${REMOTE_DIR}/haproxy-https.cfg" 2>/dev/null; then
|
||
echo " [OK] haproxy-https.cfg(语法;运行需 /etc/ssl/haproxy.pem)"
|
||
else
|
||
echo " [SKIP] haproxy-https.cfg(缺证书)"
|
||
fi
|
||
|
||
if [[ $SYNTAX_FAIL -eq 1 ]]; then
|
||
echo "[ERR] 部分 cfg 语法校验失败" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ $CFG_ONLY -eq 1 ]]; then
|
||
echo
|
||
echo "[PASS] 本目录 HAProxy cfg 语法校验通过(见 ansible/files/01-08-haproxy/README.md)"
|
||
exit 0
|
||
fi
|
||
|
||
# 3. SSH onecloud 执行 curl 验证
|
||
echo "[3/4] 经 ${VERIFY_HOST} 验证 HTTP(${OPENWRT_IP}:${HTTP_PORT})..."
|
||
|
||
# HTTP:TLS 矩阵(有 --https-hosts)按 Host 验证;否则 02-05 路径 /demo-m1~m4
|
||
if [[ -n "$HTTPS_HOSTS" ]]; then
|
||
# TLS 矩阵:按 Host 验证,test01~test04 对应 M1~M4
|
||
IFS=',' read -ra HOSTS <<< "$HTTPS_HOSTS"
|
||
HTTP_FAIL=0
|
||
for i in "${!HOSTS[@]}"; do
|
||
host="${HOSTS[$i]}"
|
||
expect="M$((i+1))"
|
||
code=$(ssh "$VERIFY_HOST" "curl -s -o /dev/null -w '%{http_code}' --max-time 5 'http://${host}:${HTTP_PORT}/' --resolve '${host}:${HTTP_PORT}:${OPENWRT_IP}' 2>/dev/null" || echo "000")
|
||
body=$(ssh "$VERIFY_HOST" "curl -s --max-time 5 'http://${host}:${HTTP_PORT}/' --resolve '${host}:${HTTP_PORT}:${OPENWRT_IP}' 2>/dev/null" || echo "")
|
||
if [[ "$code" != "200" ]]; then
|
||
echo " [FAIL] http://${host}:${HTTP_PORT}/ 返回 ${code}" >&2
|
||
HTTP_FAIL=1
|
||
elif [[ "$body" != *"$expect"* ]]; then
|
||
echo " [FAIL] http://${host}:${HTTP_PORT}/ body 不含 ${expect}" >&2
|
||
HTTP_FAIL=1
|
||
else
|
||
echo " [OK] http://${host}:${HTTP_PORT}/ 200 含 ${expect}"
|
||
fi
|
||
done
|
||
else
|
||
# 02-05 路径型
|
||
DEMO_PATHS=(demo-m1:M1 demo-m2:M2 demo-m3:M3 demo-m4:M4)
|
||
HTTP_FAIL=0
|
||
for item in "${DEMO_PATHS[@]}"; do
|
||
path="${item%%:*}"
|
||
expect="${item##*:}"
|
||
code=$(ssh "$VERIFY_HOST" "curl -s -o /dev/null -w '%{http_code}' --max-time 5 'http://${OPENWRT_IP}:${HTTP_PORT}/${path}/' 2>/dev/null" || echo "000")
|
||
body=$(ssh "$VERIFY_HOST" "curl -s --max-time 5 'http://${OPENWRT_IP}:${HTTP_PORT}/${path}/' 2>/dev/null" || echo "")
|
||
if [[ "$code" != "200" ]]; then
|
||
echo " [FAIL] /${path}/ 返回 ${code}" >&2
|
||
HTTP_FAIL=1
|
||
elif [[ "$body" != *"$expect"* ]]; then
|
||
echo " [FAIL] /${path}/ body 不含 ${expect}" >&2
|
||
HTTP_FAIL=1
|
||
else
|
||
echo " [OK] /${path}/ 200 含 ${expect}"
|
||
fi
|
||
done
|
||
fi
|
||
|
||
if [[ $HTTP_FAIL -eq 1 ]]; then
|
||
echo "[ERR] HTTP 验证失败" >&2
|
||
exit 1
|
||
fi
|
||
|
||
# 4. HTTPS 验证(需 --https-hosts,不带 -k 校验证书)
|
||
if [[ -n "$HTTPS_HOSTS" ]]; then
|
||
echo "[4/4] 经 ${VERIFY_HOST} 验证 HTTPS(域名 :${HTTPS_PORT},校验 ACME 证书)..."
|
||
IFS=',' read -ra HOSTS <<< "$HTTPS_HOSTS"
|
||
HTTPS_FAIL=0
|
||
for i in "${!HOSTS[@]}"; do
|
||
host="${HOSTS[$i]}"
|
||
expect="M$((i+1))"
|
||
code=$(ssh "$VERIFY_HOST" "curl -s -o /dev/null -w '%{http_code}' --max-time 10 'https://${host}:${HTTPS_PORT}/' --resolve '${host}:${HTTPS_PORT}:${OPENWRT_IP}' 2>/dev/null" || echo "000")
|
||
body=$(ssh "$VERIFY_HOST" "curl -s --max-time 10 'https://${host}:${HTTPS_PORT}/' --resolve '${host}:${HTTPS_PORT}:${OPENWRT_IP}' 2>/dev/null" || echo "")
|
||
if [[ "$code" != "200" ]]; then
|
||
echo " [FAIL] https://${host}:${HTTPS_PORT}/ 返回 ${code}" >&2
|
||
HTTPS_FAIL=1
|
||
elif [[ "$body" != *"$expect"* ]]; then
|
||
echo " [FAIL] https://${host}:${HTTPS_PORT}/ body 不含 ${expect}" >&2
|
||
HTTPS_FAIL=1
|
||
else
|
||
echo " [OK] https://${host}:${HTTPS_PORT}/ 200 含 ${expect}"
|
||
fi
|
||
done
|
||
if [[ $HTTPS_FAIL -eq 1 ]]; then
|
||
echo "[ERR] HTTPS 验证失败" >&2
|
||
exit 1
|
||
fi
|
||
else
|
||
echo "[4/4] 跳过 HTTPS(未指定 --https-hosts)"
|
||
fi
|
||
|
||
echo
|
||
echo "[PASS] HAProxy 验证通过"
|
||
|
||
# 5. 可选:更新验证矩阵
|
||
if [[ $UPDATE_MATRIX -eq 1 ]] && [[ -f "$MATRIX_FILE" ]]; then
|
||
TODAY=$(date +%Y-%m-%d)
|
||
echo "[INFO] 更新验证矩阵..."
|
||
if command -v python3 >/dev/null 2>&1; then
|
||
python3 "${ROOT_DIR}/scripts/01-08-update-verify-matrix.py" "$MATRIX_FILE" "$TODAY" || echo " [WARN] 验证矩阵未更新"
|
||
else
|
||
echo " [WARN] 未找到 python3,请手动更新 docs/00-02-验证矩阵.md"
|
||
fi
|
||
fi
|