Files
Deploy-Laboratory/scripts/01-08-verify-haproxy.sh
jack 8a54cac61f feat: CoreDNS IPv4 上游、03-03 Tomcat 修复、HAProxy 与验证脚本
- 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
2026-03-22 19:02:46 +08:00

212 lines
8.3 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 校验域名M1M4 对应(缺省时不校验 HTTPS
--update-matrix 验证通过后更新验证矩阵(默认启用)
--no-update-matrix 不更新验证矩阵
-h, --help 显示帮助
前置ssh openwrt 可用;完整验证还需 ssh onecloudOpenWrt 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}..."
# HTTPTLS 矩阵(有 --https-hosts按 Host 验证;否则 02-05 路径 /demo-m1m4
if [[ -n "$HTTPS_HOSTS" ]]; then
# TLS 矩阵:按 Host 验证test01test04 对应 M1M4
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