a7711d2dc3
新增 pingora-gateway 独立二进制 crate,覆盖路由、静态资源、压缩、接流保护、TLS 直连和访问日志能力。 新增 Nginx canary、realpath canary、direct preflight、direct live、direct enable 和 rollback 脚本。 新增 Pingora 切流证据包、命令证据、manifest 验真、根目录总审计和 release readiness 聚合门禁。 完善 API release、Jenkins、systemd、health patrol、生产部署和发布包自包含校验。 更新 Pingora 试点文档、Nginx README 与 Hermes 共享记忆。
910 lines
33 KiB
Bash
910 lines
33 KiB
Bash
#!/usr/bin/env bash
|
||
|
||
set -euo pipefail
|
||
|
||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
|
||
REPO_ROOT="$(cd -- "${SCRIPT_DIR}/../.." >/dev/null 2>&1 && pwd)"
|
||
SERVICE_NAME="${GENARRATIVE_PINGORA_GATEWAY_SERVICE:-genarrative-pingora-gateway.service}"
|
||
DEFAULT_SERVICE_UNIT_PATH="${REPO_ROOT}/deploy/systemd/genarrative-pingora-gateway.service"
|
||
SERVICE_UNIT_PATH="${GENARRATIVE_PINGORA_DIRECT_SERVICE_UNIT_PATH:-${DEFAULT_SERVICE_UNIT_PATH}}"
|
||
DEFAULT_TEMPLATE_PATH="${REPO_ROOT}/deploy/systemd/genarrative-pingora-gateway-direct-entry.conf"
|
||
TEMPLATE_PATH="${GENARRATIVE_PINGORA_DIRECT_TEMPLATE_PATH:-${DEFAULT_TEMPLATE_PATH}}"
|
||
DROPIN_PATH="${GENARRATIVE_PINGORA_DIRECT_DROPIN_PATH:-/etc/systemd/system/genarrative-pingora-gateway.service.d/direct-entry.conf}"
|
||
PREFLIGHT_SCRIPT="${GENARRATIVE_PINGORA_DIRECT_PREFLIGHT_SCRIPT:-${REPO_ROOT}/scripts/check-pingora-direct-preflight.mjs}"
|
||
PREFLIGHT_ENV_FILE="${GENARRATIVE_PINGORA_DIRECT_PREFLIGHT_ENV_FILE:-}"
|
||
CURRENT_RELEASE_AUDIT_SCRIPT="${GENARRATIVE_PINGORA_DIRECT_CURRENT_RELEASE_AUDIT_SCRIPT:-${REPO_ROOT}/scripts/ops/pingora-current-release-audit.mjs}"
|
||
CURRENT_RELEASE_ROOT="${GENARRATIVE_PINGORA_DIRECT_CURRENT_RELEASE_ROOT:-${REPO_ROOT}}"
|
||
CURRENT_RELEASE_AUDIT_TIMEOUT_MS="${GENARRATIVE_PINGORA_DIRECT_CURRENT_RELEASE_AUDIT_TIMEOUT_MS:-}"
|
||
PREFLIGHT_SYSTEMD="false"
|
||
PREFLIGHT_CHECK_CERT_READABLE="false"
|
||
PREFLIGHT_CHECK_SERVICE_ENV_FILE="false"
|
||
PREFLIGHT_CHECK_SERVICE_USER_CERT_READABLE="false"
|
||
PREFLIGHT_CHECK_SERVICE_BINARY_EXECUTABLE="false"
|
||
PREFLIGHT_CHECK_PORTS_FREE="false"
|
||
DIRECT_LIVE_SCRIPT="${GENARRATIVE_PINGORA_DIRECT_LIVE_SCRIPT:-${REPO_ROOT}/scripts/check-pingora-direct-live.mjs}"
|
||
DIRECT_HTTPS_BASE_URL="${GENARRATIVE_PINGORA_DIRECT_HTTPS_BASE_URL:-}"
|
||
DIRECT_HTTP_BASE_URL="${GENARRATIVE_PINGORA_DIRECT_HTTP_BASE_URL:-}"
|
||
DIRECT_HOST="${GENARRATIVE_PINGORA_DIRECT_HOST:-}"
|
||
DIRECT_REDIRECT_HOST="${GENARRATIVE_PINGORA_DIRECT_REDIRECT_HOST:-}"
|
||
DIRECT_PROBE_TOKEN="${GENARRATIVE_PINGORA_DIRECT_PROBE_TOKEN:-}"
|
||
DIRECT_PINGORA_ACCESS_LOG="${GENARRATIVE_PINGORA_DIRECT_PINGORA_ACCESS_LOG:-}"
|
||
DIRECT_ACCESS_LOG_SINCE_LINES="${GENARRATIVE_PINGORA_DIRECT_ACCESS_LOG_SINCE_LINES:-}"
|
||
DIRECT_SPACETIME_DATABASE="${GENARRATIVE_PINGORA_DIRECT_SPACETIME_DATABASE:-}"
|
||
DIRECT_TIMEOUT_MS="${GENARRATIVE_PINGORA_DIRECT_TIMEOUT_MS:-}"
|
||
APPLY="false"
|
||
STATUS_AFTER="true"
|
||
VERIFY_SYSTEMD_AFTER="true"
|
||
|
||
usage() {
|
||
cat <<'EOF'
|
||
用法:
|
||
scripts/deploy/pingora-direct-enable.sh [--apply] [--preflight-env-file <path>] [--preflight-systemd] [--preflight-check-cert-readable] [--preflight-check-service-env-file] [--preflight-check-service-user-cert-readable] [--preflight-check-service-binary-executable] [--preflight-check-ports-free]
|
||
[--direct-https-base-url <url>] [--direct-http-base-url <url>] [--direct-host <host>] [--direct-redirect-host <host>]
|
||
[--direct-spacetime-database <name>] [--direct-probe-token <token>] [--direct-pingora-access-log <path>] [--direct-access-log-since-lines <count>] [--direct-timeout-ms <ms>] [--direct-live-script <path>] [--no-postcheck]
|
||
[--current-release-audit-script <path>] [--current-release-root <path>] [--current-release-audit-timeout-ms <ms>]
|
||
[--service <name>] [--service-unit-path <path>] [--template-path <path>] [--dropin-path <path>]
|
||
|
||
说明:
|
||
启用 Pingora 直连低端口入口:把已准备好的 direct-entry systemd drop-in 模板安装到
|
||
genarrative-pingora-gateway.service.d/direct-entry.conf,执行 daemon-reload,
|
||
重启 genarrative-pingora-gateway.service,让服务具备绑定 80/443 的最小 capability。
|
||
|
||
默认是 dry-run,只打印将执行的命令;必须显式传 --apply 才会修改系统状态。
|
||
该脚本不写入 TLS env、不复制证书、不停止 Nginx;--apply 会先执行 current release 自包含自审,
|
||
确认发布包已携带 Pingora 网关且 systemd ExecStart 指向随包二进制;--apply 时必须提供 --preflight-env-file、
|
||
--preflight-check-cert-readable、--preflight-check-service-env-file、--preflight-check-service-user-cert-readable、--preflight-check-service-binary-executable、--preflight-check-ports-free 和 direct live smoke 参数,
|
||
先通过 direct preflight,安装并重启 Pingora,再通过 direct live smoke 后才视为启用成功。
|
||
EOF
|
||
}
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
-h|--help)
|
||
usage
|
||
exit 0
|
||
;;
|
||
--apply)
|
||
APPLY="true"
|
||
shift
|
||
;;
|
||
--no-status)
|
||
STATUS_AFTER="false"
|
||
shift
|
||
;;
|
||
--no-postcheck)
|
||
VERIFY_SYSTEMD_AFTER="false"
|
||
shift
|
||
;;
|
||
--service)
|
||
SERVICE_NAME="${2:-}"
|
||
if [[ -z "${SERVICE_NAME}" ]]; then
|
||
echo "[pingora-direct-enable] --service 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--service-unit-path)
|
||
SERVICE_UNIT_PATH="${2:-}"
|
||
if [[ -z "${SERVICE_UNIT_PATH}" ]]; then
|
||
echo "[pingora-direct-enable] --service-unit-path 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--template-path)
|
||
TEMPLATE_PATH="${2:-}"
|
||
if [[ -z "${TEMPLATE_PATH}" ]]; then
|
||
echo "[pingora-direct-enable] --template-path 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--dropin-path)
|
||
DROPIN_PATH="${2:-}"
|
||
if [[ -z "${DROPIN_PATH}" ]]; then
|
||
echo "[pingora-direct-enable] --dropin-path 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--preflight-script)
|
||
PREFLIGHT_SCRIPT="${2:-}"
|
||
if [[ -z "${PREFLIGHT_SCRIPT}" ]]; then
|
||
echo "[pingora-direct-enable] --preflight-script 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--preflight-env-file)
|
||
PREFLIGHT_ENV_FILE="${2:-}"
|
||
if [[ -z "${PREFLIGHT_ENV_FILE}" ]]; then
|
||
echo "[pingora-direct-enable] --preflight-env-file 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--current-release-audit-script)
|
||
CURRENT_RELEASE_AUDIT_SCRIPT="${2:-}"
|
||
if [[ -z "${CURRENT_RELEASE_AUDIT_SCRIPT}" ]]; then
|
||
echo "[pingora-direct-enable] --current-release-audit-script 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--current-release-root)
|
||
CURRENT_RELEASE_ROOT="${2:-}"
|
||
if [[ -z "${CURRENT_RELEASE_ROOT}" ]]; then
|
||
echo "[pingora-direct-enable] --current-release-root 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--current-release-audit-timeout-ms)
|
||
CURRENT_RELEASE_AUDIT_TIMEOUT_MS="${2:-}"
|
||
if [[ -z "${CURRENT_RELEASE_AUDIT_TIMEOUT_MS}" ]]; then
|
||
echo "[pingora-direct-enable] --current-release-audit-timeout-ms 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--preflight-systemd)
|
||
PREFLIGHT_SYSTEMD="true"
|
||
shift
|
||
;;
|
||
--preflight-check-cert-readable)
|
||
PREFLIGHT_CHECK_CERT_READABLE="true"
|
||
shift
|
||
;;
|
||
--preflight-check-service-env-file)
|
||
PREFLIGHT_CHECK_SERVICE_ENV_FILE="true"
|
||
shift
|
||
;;
|
||
--preflight-check-service-user-cert-readable)
|
||
PREFLIGHT_CHECK_SERVICE_USER_CERT_READABLE="true"
|
||
shift
|
||
;;
|
||
--preflight-check-service-binary-executable)
|
||
PREFLIGHT_CHECK_SERVICE_BINARY_EXECUTABLE="true"
|
||
shift
|
||
;;
|
||
--preflight-check-ports-free)
|
||
PREFLIGHT_CHECK_PORTS_FREE="true"
|
||
shift
|
||
;;
|
||
--direct-live-script)
|
||
DIRECT_LIVE_SCRIPT="${2:-}"
|
||
if [[ -z "${DIRECT_LIVE_SCRIPT}" ]]; then
|
||
echo "[pingora-direct-enable] --direct-live-script 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--direct-https-base-url)
|
||
DIRECT_HTTPS_BASE_URL="${2:-}"
|
||
if [[ -z "${DIRECT_HTTPS_BASE_URL}" ]]; then
|
||
echo "[pingora-direct-enable] --direct-https-base-url 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--direct-http-base-url)
|
||
DIRECT_HTTP_BASE_URL="${2:-}"
|
||
if [[ -z "${DIRECT_HTTP_BASE_URL}" ]]; then
|
||
echo "[pingora-direct-enable] --direct-http-base-url 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--direct-host)
|
||
DIRECT_HOST="${2:-}"
|
||
if [[ -z "${DIRECT_HOST}" ]]; then
|
||
echo "[pingora-direct-enable] --direct-host 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--direct-redirect-host)
|
||
DIRECT_REDIRECT_HOST="${2:-}"
|
||
if [[ -z "${DIRECT_REDIRECT_HOST}" ]]; then
|
||
echo "[pingora-direct-enable] --direct-redirect-host 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--direct-probe-token)
|
||
DIRECT_PROBE_TOKEN="${2:-}"
|
||
if [[ -z "${DIRECT_PROBE_TOKEN}" ]]; then
|
||
echo "[pingora-direct-enable] --direct-probe-token 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--direct-pingora-access-log)
|
||
DIRECT_PINGORA_ACCESS_LOG="${2:-}"
|
||
if [[ -z "${DIRECT_PINGORA_ACCESS_LOG}" ]]; then
|
||
echo "[pingora-direct-enable] --direct-pingora-access-log 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--direct-access-log-since-lines)
|
||
DIRECT_ACCESS_LOG_SINCE_LINES="${2:-}"
|
||
if [[ -z "${DIRECT_ACCESS_LOG_SINCE_LINES}" ]]; then
|
||
echo "[pingora-direct-enable] --direct-access-log-since-lines 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--direct-spacetime-database)
|
||
DIRECT_SPACETIME_DATABASE="${2:-}"
|
||
if [[ -z "${DIRECT_SPACETIME_DATABASE}" ]]; then
|
||
echo "[pingora-direct-enable] --direct-spacetime-database 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
--direct-timeout-ms)
|
||
DIRECT_TIMEOUT_MS="${2:-}"
|
||
if [[ -z "${DIRECT_TIMEOUT_MS}" ]]; then
|
||
echo "[pingora-direct-enable] --direct-timeout-ms 缺少参数" >&2
|
||
exit 1
|
||
fi
|
||
shift 2
|
||
;;
|
||
*)
|
||
echo "[pingora-direct-enable] 未知参数: $1" >&2
|
||
usage >&2
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
reject_control_characters() {
|
||
local label="$1"
|
||
local value="$2"
|
||
if [[ "${value}" == *$'\n'* || "${value}" == *$'\r'* ]]; then
|
||
echo "[pingora-direct-enable] ${label} 不能包含换行或 NUL 字符。" >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
is_filesystem_root_path() {
|
||
local value="$1"
|
||
local without_slashes="${value//\//}"
|
||
[[ -n "${value}" && -z "${without_slashes}" ]]
|
||
}
|
||
|
||
reject_filesystem_root_path() {
|
||
local label="$1"
|
||
local value="$2"
|
||
if is_filesystem_root_path "${value}"; then
|
||
echo "[pingora-direct-enable] ${label} 不能是文件系统根目录。" >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
reject_control_characters "--service" "${SERVICE_NAME}"
|
||
reject_control_characters "--service-unit-path" "${SERVICE_UNIT_PATH}"
|
||
reject_control_characters "--template-path" "${TEMPLATE_PATH}"
|
||
reject_control_characters "--dropin-path" "${DROPIN_PATH}"
|
||
reject_control_characters "--preflight-script" "${PREFLIGHT_SCRIPT}"
|
||
reject_control_characters "--preflight-env-file" "${PREFLIGHT_ENV_FILE}"
|
||
reject_control_characters "--current-release-audit-script" "${CURRENT_RELEASE_AUDIT_SCRIPT}"
|
||
reject_control_characters "--current-release-root" "${CURRENT_RELEASE_ROOT}"
|
||
reject_control_characters "--current-release-audit-timeout-ms" "${CURRENT_RELEASE_AUDIT_TIMEOUT_MS}"
|
||
reject_control_characters "--direct-live-script" "${DIRECT_LIVE_SCRIPT}"
|
||
reject_control_characters "--direct-https-base-url" "${DIRECT_HTTPS_BASE_URL}"
|
||
reject_control_characters "--direct-http-base-url" "${DIRECT_HTTP_BASE_URL}"
|
||
reject_control_characters "--direct-host" "${DIRECT_HOST}"
|
||
reject_control_characters "--direct-redirect-host" "${DIRECT_REDIRECT_HOST}"
|
||
reject_control_characters "--direct-probe-token" "${DIRECT_PROBE_TOKEN}"
|
||
reject_control_characters "--direct-pingora-access-log" "${DIRECT_PINGORA_ACCESS_LOG}"
|
||
reject_control_characters "--direct-access-log-since-lines" "${DIRECT_ACCESS_LOG_SINCE_LINES}"
|
||
reject_control_characters "--direct-spacetime-database" "${DIRECT_SPACETIME_DATABASE}"
|
||
reject_control_characters "--direct-timeout-ms" "${DIRECT_TIMEOUT_MS}"
|
||
|
||
reject_filesystem_root_path "--service-unit-path" "${SERVICE_UNIT_PATH}"
|
||
reject_filesystem_root_path "--template-path" "${TEMPLATE_PATH}"
|
||
reject_filesystem_root_path "--dropin-path" "${DROPIN_PATH}"
|
||
reject_filesystem_root_path "--preflight-env-file" "${PREFLIGHT_ENV_FILE}"
|
||
reject_filesystem_root_path "--preflight-script" "${PREFLIGHT_SCRIPT}"
|
||
reject_filesystem_root_path "--current-release-audit-script" "${CURRENT_RELEASE_AUDIT_SCRIPT}"
|
||
reject_filesystem_root_path "--current-release-root" "${CURRENT_RELEASE_ROOT}"
|
||
reject_filesystem_root_path "--direct-live-script" "${DIRECT_LIVE_SCRIPT}"
|
||
reject_filesystem_root_path "--direct-pingora-access-log" "${DIRECT_PINGORA_ACCESS_LOG}"
|
||
|
||
if [[ "${TEMPLATE_PATH}" != /* ]]; then
|
||
echo "[pingora-direct-enable] --template-path 必须是绝对路径: ${TEMPLATE_PATH}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${SERVICE_UNIT_PATH}" != /* ]]; then
|
||
echo "[pingora-direct-enable] --service-unit-path 必须是绝对路径: ${SERVICE_UNIT_PATH}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${DROPIN_PATH}" != /* ]]; then
|
||
echo "[pingora-direct-enable] --dropin-path 必须是绝对路径: ${DROPIN_PATH}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ -n "${PREFLIGHT_ENV_FILE}" && "${PREFLIGHT_ENV_FILE}" != /* ]]; then
|
||
echo "[pingora-direct-enable] --preflight-env-file 必须是绝对路径: ${PREFLIGHT_ENV_FILE}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${PREFLIGHT_SCRIPT}" != /* ]]; then
|
||
echo "[pingora-direct-enable] --preflight-script 必须是绝对路径: ${PREFLIGHT_SCRIPT}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${CURRENT_RELEASE_AUDIT_SCRIPT}" != /* ]]; then
|
||
echo "[pingora-direct-enable] --current-release-audit-script 必须是绝对路径: ${CURRENT_RELEASE_AUDIT_SCRIPT}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${CURRENT_RELEASE_ROOT}" != /* ]]; then
|
||
echo "[pingora-direct-enable] --current-release-root 必须是绝对路径: ${CURRENT_RELEASE_ROOT}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${DIRECT_LIVE_SCRIPT}" != /* ]]; then
|
||
echo "[pingora-direct-enable] --direct-live-script 必须是绝对路径: ${DIRECT_LIVE_SCRIPT}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && -z "${PREFLIGHT_ENV_FILE}" ]]; then
|
||
echo "[pingora-direct-enable] --apply 必须同时提供 --preflight-env-file,避免跳过直连 env / 证书预检。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && "${PREFLIGHT_CHECK_CERT_READABLE}" != "true" ]]; then
|
||
echo "[pingora-direct-enable] --apply 必须同时提供 --preflight-check-cert-readable,避免跳过 TLS 证书和私钥可读预检。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && "${PREFLIGHT_CHECK_SERVICE_ENV_FILE}" != "true" ]]; then
|
||
echo "[pingora-direct-enable] --apply 必须同时提供 --preflight-check-service-env-file,避免检查的 env 文件和 systemd service 实际读取的 EnvironmentFile 不一致。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && "${PREFLIGHT_CHECK_SERVICE_USER_CERT_READABLE}" != "true" ]]; then
|
||
echo "[pingora-direct-enable] --apply 必须同时提供 --preflight-check-service-user-cert-readable,避免跳过 systemd 服务用户读取 TLS 证书和私钥预检。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && "${PREFLIGHT_CHECK_SERVICE_BINARY_EXECUTABLE}" != "true" ]]; then
|
||
echo "[pingora-direct-enable] --apply 必须同时提供 --preflight-check-service-binary-executable,避免 current release 缺少可执行 pingora-gateway 时才在重启阶段失败。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && "${PREFLIGHT_CHECK_PORTS_FREE}" != "true" ]]; then
|
||
echo "[pingora-direct-enable] --apply 必须同时提供 --preflight-check-ports-free,避免 Nginx 或其它进程仍占用 80/443。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && -z "${DIRECT_HTTPS_BASE_URL}" ]]; then
|
||
echo "[pingora-direct-enable] --apply 必须同时提供 --direct-https-base-url,启用后验证 Pingora HTTPS 直连入口。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && -z "${DIRECT_HTTP_BASE_URL}" ]]; then
|
||
echo "[pingora-direct-enable] --apply 必须同时提供 --direct-http-base-url,启用后验证 HTTP redirect / ACME 入口。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && -z "${DIRECT_HOST}" ]]; then
|
||
echo "[pingora-direct-enable] --apply 必须同时提供 --direct-host,启用后用正式域名 Host/SNI 验证直连入口。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && -z "${DIRECT_REDIRECT_HOST}" ]]; then
|
||
echo "[pingora-direct-enable] --apply 必须同时提供 --direct-redirect-host,启用后验证 HTTP redirect Location host。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && -z "${DIRECT_PINGORA_ACCESS_LOG}" ]]; then
|
||
echo "[pingora-direct-enable] --apply 必须同时提供 --direct-pingora-access-log,启用后验证直连请求已写入 Pingora access log。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ -n "${DIRECT_PINGORA_ACCESS_LOG}" && "${DIRECT_PINGORA_ACCESS_LOG}" != /* ]]; then
|
||
echo "[pingora-direct-enable] --direct-pingora-access-log 必须是绝对路径: ${DIRECT_PINGORA_ACCESS_LOG}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && -z "${DIRECT_SPACETIME_DATABASE}" ]]; then
|
||
echo "[pingora-direct-enable] --apply 必须同时提供 --direct-spacetime-database,启用后验证目标库 WSS subscribe。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && ! -f "${TEMPLATE_PATH}" ]]; then
|
||
echo "[pingora-direct-enable] direct-entry 模板不存在: ${TEMPLATE_PATH}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && ! -f "${SERVICE_UNIT_PATH}" ]]; then
|
||
echo "[pingora-direct-enable] 主 service 模板不存在: ${SERVICE_UNIT_PATH}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && ! -f "${CURRENT_RELEASE_AUDIT_SCRIPT}" ]]; then
|
||
echo "[pingora-direct-enable] current release 自审脚本不存在: ${CURRENT_RELEASE_AUDIT_SCRIPT}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && ! -f "${PREFLIGHT_SCRIPT}" ]]; then
|
||
echo "[pingora-direct-enable] direct preflight 脚本不存在: ${PREFLIGHT_SCRIPT}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" && ! -f "${DIRECT_LIVE_SCRIPT}" ]]; then
|
||
echo "[pingora-direct-enable] direct live smoke 脚本不存在: ${DIRECT_LIVE_SCRIPT}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" == "true" ]]; then
|
||
DROPIN_DIR="$(dirname "${DROPIN_PATH}")"
|
||
if [[ -L "${DROPIN_DIR}" ]]; then
|
||
echo "[pingora-direct-enable] drop-in 目录不能是符号链接: ${DROPIN_DIR}" >&2
|
||
exit 1
|
||
fi
|
||
if [[ -e "${DROPIN_DIR}" && ! -d "${DROPIN_DIR}" ]]; then
|
||
echo "[pingora-direct-enable] drop-in 父路径必须是目录: ${DROPIN_DIR}" >&2
|
||
exit 1
|
||
fi
|
||
if [[ -L "${DROPIN_PATH}" ]]; then
|
||
echo "[pingora-direct-enable] drop-in 目标不能是符号链接: ${DROPIN_PATH}" >&2
|
||
exit 1
|
||
fi
|
||
if [[ -e "${DROPIN_PATH}" && ! -f "${DROPIN_PATH}" ]]; then
|
||
echo "[pingora-direct-enable] drop-in 目标已存在但不是普通文件: ${DROPIN_PATH}" >&2
|
||
exit 1
|
||
fi
|
||
fi
|
||
|
||
run_cmd() {
|
||
echo "+ $*"
|
||
if [[ "${APPLY}" == "true" ]]; then
|
||
"$@"
|
||
fi
|
||
}
|
||
|
||
print_redacted_command() {
|
||
local previous="" output=()
|
||
for arg in "$@"; do
|
||
if [[ "${previous}" == "--probe-token" || "${previous}" == "--direct-probe-token" ]]; then
|
||
output+=("<redacted>")
|
||
else
|
||
output+=("${arg}")
|
||
fi
|
||
previous="${arg}"
|
||
done
|
||
echo "+ ${output[*]}"
|
||
}
|
||
|
||
run_systemctl() {
|
||
if [[ "${APPLY}" != "true" ]]; then
|
||
run_cmd systemctl "$@"
|
||
return
|
||
fi
|
||
if command -v systemctl >/dev/null 2>&1; then
|
||
run_cmd systemctl "$@"
|
||
else
|
||
echo "[pingora-direct-enable] 未找到 systemctl,无法执行: systemctl $*" >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
run_preflight() {
|
||
if [[ -z "${PREFLIGHT_ENV_FILE}" ]]; then
|
||
echo "[pingora-direct-enable] 未提供 --preflight-env-file,仅执行脚本 dry-run;--apply 会强制要求预检。"
|
||
return
|
||
fi
|
||
|
||
preflight_args=(
|
||
"${PREFLIGHT_SCRIPT}"
|
||
--env-file "${PREFLIGHT_ENV_FILE}"
|
||
--require-live-env
|
||
)
|
||
if [[ "${PREFLIGHT_SYSTEMD}" == "true" ]]; then
|
||
preflight_args+=(--systemd-cat)
|
||
fi
|
||
if [[ "${PREFLIGHT_CHECK_CERT_READABLE}" == "true" ]]; then
|
||
preflight_args+=(--check-cert-readable)
|
||
fi
|
||
if [[ "${PREFLIGHT_CHECK_SERVICE_ENV_FILE}" == "true" ]]; then
|
||
preflight_args+=(--check-service-env-file)
|
||
fi
|
||
if [[ "${PREFLIGHT_CHECK_SERVICE_USER_CERT_READABLE}" == "true" ]]; then
|
||
preflight_args+=(--check-service-user-cert-readable)
|
||
fi
|
||
if [[ "${PREFLIGHT_CHECK_SERVICE_BINARY_EXECUTABLE}" == "true" ]]; then
|
||
preflight_args+=(--check-service-binary-executable)
|
||
fi
|
||
if [[ "${PREFLIGHT_CHECK_PORTS_FREE}" == "true" ]]; then
|
||
preflight_args+=(--check-ports-free)
|
||
fi
|
||
|
||
echo "+ node -- ${preflight_args[*]}"
|
||
node -- "${preflight_args[@]}"
|
||
}
|
||
|
||
run_current_release_audit() {
|
||
audit_args=(
|
||
"${CURRENT_RELEASE_AUDIT_SCRIPT}"
|
||
--release-root "${CURRENT_RELEASE_ROOT}"
|
||
--require-pingora-gateway
|
||
--systemd-show
|
||
--systemd-service "${SERVICE_NAME}"
|
||
)
|
||
if [[ -n "${CURRENT_RELEASE_AUDIT_TIMEOUT_MS}" ]]; then
|
||
audit_args+=(--timeout-ms "${CURRENT_RELEASE_AUDIT_TIMEOUT_MS}")
|
||
fi
|
||
|
||
echo "+ node -- ${audit_args[*]}"
|
||
if [[ "${APPLY}" != "true" ]]; then
|
||
echo "[pingora-direct-enable] dry-run:--apply 前会先执行 current release 自包含自审。"
|
||
return
|
||
fi
|
||
|
||
node -- "${audit_args[@]}"
|
||
}
|
||
|
||
systemd_env_file_matches() {
|
||
local expected="$1"
|
||
local line value word normalized
|
||
while IFS= read -r line; do
|
||
line="${line#"${line%%[![:space:]]*}"}"
|
||
line="${line%"${line##*[![:space:]]}"}"
|
||
[[ "${line}" == EnvironmentFile=* ]] || continue
|
||
value="${line#EnvironmentFile=}"
|
||
[[ -n "${value}" ]] || continue
|
||
for word in ${value}; do
|
||
normalized="${word%\"}"
|
||
normalized="${normalized#\"}"
|
||
normalized="${normalized%\'}"
|
||
normalized="${normalized#\'}"
|
||
normalized="${normalized#-}"
|
||
if [[ "${normalized}" == "${expected}" ]]; then
|
||
return 0
|
||
fi
|
||
done
|
||
done <<<"${unit_content}"
|
||
return 1
|
||
}
|
||
|
||
read_expected_exec_start() {
|
||
local line value
|
||
if [[ ! -f "${SERVICE_UNIT_PATH}" ]]; then
|
||
return 1
|
||
fi
|
||
while IFS= read -r line; do
|
||
line="${line#"${line%%[![:space:]]*}"}"
|
||
line="${line%"${line##*[![:space:]]}"}"
|
||
[[ "${line}" == ExecStart=* ]] || continue
|
||
value="${line#ExecStart=}"
|
||
[[ -n "${value}" ]] || continue
|
||
printf '%s\n' "${value}"
|
||
return 0
|
||
done <"${SERVICE_UNIT_PATH}"
|
||
return 1
|
||
}
|
||
|
||
first_exec_word() {
|
||
local value="$1"
|
||
value="${value#"${value%%[![:space:]]*}"}"
|
||
value="${value%"${value##*[![:space:]]}"}"
|
||
if [[ "${value}" == \"* ]]; then
|
||
value="${value#\"}"
|
||
printf '%s\n' "${value%%\"*}"
|
||
return
|
||
fi
|
||
printf '%s\n' "${value%%[[:space:]]*}"
|
||
}
|
||
|
||
systemd_show_exec_start_matches() {
|
||
local expected_exec="$1"
|
||
local expected_binary actual_show actual_binary
|
||
expected_binary="$(first_exec_word "${expected_exec}")"
|
||
[[ -n "${expected_binary}" ]] || return 1
|
||
actual_show="$(systemctl show "${SERVICE_NAME}" --property=ExecStart --value --no-pager)"
|
||
actual_binary="${actual_show}"
|
||
if [[ "${actual_show}" == *"path="* ]]; then
|
||
actual_binary="${actual_show#*path=}"
|
||
actual_binary="${actual_binary%% ;*}"
|
||
elif [[ "${actual_show}" == ExecStart=* ]]; then
|
||
actual_binary="${actual_show#ExecStart=}"
|
||
actual_binary="$(first_exec_word "${actual_binary}")"
|
||
else
|
||
actual_binary="$(first_exec_word "${actual_binary}")"
|
||
fi
|
||
[[ "${actual_binary}" == "${expected_binary}" ]]
|
||
}
|
||
|
||
verify_systemd_exec_start() {
|
||
if [[ "${VERIFY_SYSTEMD_AFTER}" != "true" ]]; then
|
||
echo "[pingora-direct-enable] 已跳过 Pingora ExecStart 指向核验。"
|
||
return
|
||
fi
|
||
|
||
expected_exec_start="$(read_expected_exec_start || true)"
|
||
if [[ -z "${expected_exec_start}" ]]; then
|
||
echo "[pingora-direct-enable] 无法从主 service 模板读取 ExecStart: ${SERVICE_UNIT_PATH}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ "${APPLY}" != "true" ]]; then
|
||
echo "+ systemctl show ${SERVICE_NAME} --property=ExecStart --value --no-pager"
|
||
echo "[pingora-direct-enable] dry-run:--apply 后会核验 systemd ExecStart 指向主 service 模板中的 ${expected_exec_start}。"
|
||
return
|
||
fi
|
||
|
||
if ! command -v systemctl >/dev/null 2>&1; then
|
||
echo "[pingora-direct-enable] 未找到 systemctl,无法核验 Pingora ExecStart。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
echo "+ systemctl show ${SERVICE_NAME} --property=ExecStart --value --no-pager"
|
||
if ! systemd_show_exec_start_matches "${expected_exec_start}"; then
|
||
echo "[pingora-direct-enable] systemctl show ExecStart 未指向主 service 模板中的 ${expected_exec_start},请先修正 ${SERVICE_NAME} 指向 current release 网关二进制。" >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
verify_systemd_dropin() {
|
||
if [[ "${VERIFY_SYSTEMD_AFTER}" != "true" ]]; then
|
||
echo "[pingora-direct-enable] 已跳过 systemd drop-in 生效核验。"
|
||
return
|
||
fi
|
||
|
||
if [[ "${APPLY}" != "true" ]]; then
|
||
echo "+ systemctl cat ${SERVICE_NAME}"
|
||
echo "[pingora-direct-enable] dry-run:--apply 后会校验 systemd 最终配置包含 CAP_NET_BIND_SERVICE。"
|
||
return
|
||
fi
|
||
|
||
if ! command -v systemctl >/dev/null 2>&1; then
|
||
echo "[pingora-direct-enable] 未找到 systemctl,无法核验 drop-in 是否生效。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
echo "+ systemctl cat ${SERVICE_NAME}"
|
||
unit_content="$(systemctl cat "${SERVICE_NAME}")"
|
||
if [[ "${unit_content}" != *"AmbientCapabilities=CAP_NET_BIND_SERVICE"* ]]; then
|
||
echo "[pingora-direct-enable] systemctl cat 未显示 AmbientCapabilities=CAP_NET_BIND_SERVICE,direct-entry drop-in 未生效。" >&2
|
||
exit 1
|
||
fi
|
||
if [[ "${unit_content}" != *"CapabilityBoundingSet=CAP_NET_BIND_SERVICE"* ]]; then
|
||
echo "[pingora-direct-enable] systemctl cat 未显示 CapabilityBoundingSet=CAP_NET_BIND_SERVICE,direct-entry drop-in 未生效。" >&2
|
||
exit 1
|
||
fi
|
||
if [[ "${PREFLIGHT_CHECK_SERVICE_ENV_FILE}" == "true" && -n "${PREFLIGHT_ENV_FILE}" ]]; then
|
||
if ! systemd_env_file_matches "${PREFLIGHT_ENV_FILE}"; then
|
||
echo "[pingora-direct-enable] systemctl cat 未显示 EnvironmentFile=${PREFLIGHT_ENV_FILE},service 实际读取的 env 与 preflight env 不一致。" >&2
|
||
exit 1
|
||
fi
|
||
fi
|
||
}
|
||
|
||
verify_service_active_after_restart() {
|
||
if [[ "${VERIFY_SYSTEMD_AFTER}" != "true" ]]; then
|
||
echo "[pingora-direct-enable] 已跳过 Pingora 重启后状态核验。"
|
||
return
|
||
fi
|
||
|
||
if [[ "${APPLY}" != "true" ]]; then
|
||
echo "+ systemctl is-active ${SERVICE_NAME}"
|
||
echo "[pingora-direct-enable] dry-run:--apply 后会校验 Pingora service 为 active。"
|
||
return
|
||
fi
|
||
|
||
if ! command -v systemctl >/dev/null 2>&1; then
|
||
echo "[pingora-direct-enable] 未找到 systemctl,无法核验 Pingora 重启后状态。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
echo "+ systemctl is-active ${SERVICE_NAME}"
|
||
service_state="$(systemctl is-active "${SERVICE_NAME}")"
|
||
if [[ "${service_state}" != "active" ]]; then
|
||
echo "[pingora-direct-enable] Pingora 重启后状态不是 active: ${service_state}" >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
run_direct_live_smoke_after_enable() {
|
||
if [[ -z "${DIRECT_HTTPS_BASE_URL}" ]]; then
|
||
echo "+ node ${DIRECT_LIVE_SCRIPT} --https-base-url <direct-https-base-url> --http-base-url <direct-http-base-url> --host <direct-host> --redirect-host <direct-redirect-host> --spacetime-database <database> --require-wss-upgrade"
|
||
echo "[pingora-direct-enable] dry-run:--apply 后会执行 direct live smoke;--apply 会强制要求 direct live 参数。"
|
||
return
|
||
fi
|
||
|
||
direct_live_args=(
|
||
"${DIRECT_LIVE_SCRIPT}"
|
||
--https-base-url "${DIRECT_HTTPS_BASE_URL}"
|
||
)
|
||
if [[ -n "${DIRECT_HTTP_BASE_URL}" ]]; then
|
||
direct_live_args+=(--http-base-url "${DIRECT_HTTP_BASE_URL}")
|
||
fi
|
||
if [[ -n "${DIRECT_HOST}" ]]; then
|
||
direct_live_args+=(--host "${DIRECT_HOST}")
|
||
fi
|
||
if [[ -n "${DIRECT_REDIRECT_HOST}" ]]; then
|
||
direct_live_args+=(--redirect-host "${DIRECT_REDIRECT_HOST}")
|
||
fi
|
||
if [[ -n "${DIRECT_PROBE_TOKEN}" ]]; then
|
||
direct_live_args+=(--probe-token "${DIRECT_PROBE_TOKEN}")
|
||
fi
|
||
if [[ -n "${DIRECT_PINGORA_ACCESS_LOG}" ]]; then
|
||
direct_live_args+=(--pingora-access-log "${DIRECT_PINGORA_ACCESS_LOG}")
|
||
fi
|
||
if [[ -n "${DIRECT_ACCESS_LOG_SINCE_LINES}" ]]; then
|
||
direct_live_args+=(--access-log-since-lines "${DIRECT_ACCESS_LOG_SINCE_LINES}")
|
||
fi
|
||
if [[ -n "${DIRECT_SPACETIME_DATABASE}" ]]; then
|
||
direct_live_args+=(--spacetime-database "${DIRECT_SPACETIME_DATABASE}")
|
||
fi
|
||
direct_live_args+=(--require-wss-upgrade)
|
||
if [[ -n "${DIRECT_TIMEOUT_MS}" ]]; then
|
||
direct_live_args+=(--timeout-ms "${DIRECT_TIMEOUT_MS}")
|
||
fi
|
||
direct_live_args+=(--json)
|
||
|
||
print_redacted_command node "${direct_live_args[@]}"
|
||
if [[ "${APPLY}" != "true" ]]; then
|
||
echo "[pingora-direct-enable] dry-run:--apply 后会验证 Pingora HTTPS / HTTP redirect / WSS 直连入口,并解析 direct-access-log 结构化证据。"
|
||
return
|
||
fi
|
||
|
||
set +e
|
||
direct_live_output="$(node "${direct_live_args[@]}")"
|
||
direct_live_status=$?
|
||
set -e
|
||
printf '%s\n' "${direct_live_output}"
|
||
if [[ "${direct_live_status}" -ne 0 ]]; then
|
||
exit "${direct_live_status}"
|
||
fi
|
||
DIRECT_LIVE_OUTPUT="${direct_live_output}" node -- <<'NODE'
|
||
const stdout = process.env.DIRECT_LIVE_OUTPUT || '';
|
||
|
||
const jsonText = extractFirstJsonObject(stdout);
|
||
if (!jsonText) {
|
||
console.error(
|
||
'[pingora-direct-enable] direct live stdout 中未找到 JSON 结果对象,无法确认 direct-access-log 结构化证据。',
|
||
);
|
||
process.exit(1);
|
||
}
|
||
|
||
let parsed;
|
||
try {
|
||
parsed = JSON.parse(jsonText);
|
||
} catch (error) {
|
||
console.error(
|
||
`[pingora-direct-enable] direct live JSON 解析失败: ${error.message}`,
|
||
);
|
||
process.exit(1);
|
||
}
|
||
|
||
const accessLogCheck = parsed?.results?.find(
|
||
(item) => item?.name === 'direct-access-log',
|
||
);
|
||
if (!accessLogCheck) {
|
||
console.error(
|
||
'[pingora-direct-enable] direct live JSON 缺少 direct-access-log 结构化结果。',
|
||
);
|
||
process.exit(1);
|
||
}
|
||
|
||
const checked = toNonNegativeInteger(accessLogCheck.checked);
|
||
const matchedCount = toNonNegativeInteger(accessLogCheck.matchedCount);
|
||
const missingCount = toNonNegativeInteger(accessLogCheck.missingCount);
|
||
const mismatchCount = toNonNegativeInteger(accessLogCheck.mismatchCount);
|
||
const missingDetailsCount = Array.isArray(accessLogCheck.missing)
|
||
? accessLogCheck.missing.length
|
||
: null;
|
||
const mismatchDetailsCount = Array.isArray(accessLogCheck.mismatches)
|
||
? accessLogCheck.mismatches.length
|
||
: null;
|
||
|
||
if (
|
||
checked === null ||
|
||
matchedCount === null ||
|
||
missingCount !== 0 ||
|
||
mismatchCount !== 0 ||
|
||
matchedCount !== checked ||
|
||
missingDetailsCount !== 0 ||
|
||
mismatchDetailsCount !== 0
|
||
) {
|
||
console.error(
|
||
`[pingora-direct-enable] direct-access-log 结构化证据未通过: checked=${checked ?? '-'} matched=${matchedCount ?? '-'} missing=${missingCount ?? '-'} mismatches=${mismatchCount ?? '-'}`,
|
||
);
|
||
process.exit(1);
|
||
}
|
||
|
||
console.log(
|
||
`[pingora-direct-enable] direct-access-log evidence checked=${checked} matched=${matchedCount} missing=0 mismatches=0`,
|
||
);
|
||
|
||
function extractFirstJsonObject(text) {
|
||
const startIndex = text.indexOf('{');
|
||
if (startIndex < 0) {
|
||
return '';
|
||
}
|
||
let depth = 0;
|
||
let inString = false;
|
||
let escaped = false;
|
||
|
||
for (let index = startIndex; index < text.length; index += 1) {
|
||
const char = text[index];
|
||
if (inString) {
|
||
if (escaped) {
|
||
escaped = false;
|
||
} else if (char === '\\') {
|
||
escaped = true;
|
||
} else if (char === '"') {
|
||
inString = false;
|
||
}
|
||
continue;
|
||
}
|
||
if (char === '"') {
|
||
inString = true;
|
||
continue;
|
||
}
|
||
if (char === '{') {
|
||
depth += 1;
|
||
continue;
|
||
}
|
||
if (char === '}') {
|
||
depth -= 1;
|
||
if (depth === 0) {
|
||
return text.slice(startIndex, index + 1);
|
||
}
|
||
}
|
||
}
|
||
return '';
|
||
}
|
||
|
||
function toNonNegativeInteger(value) {
|
||
const number = Number(value);
|
||
if (!Number.isInteger(number) || number < 0) {
|
||
return null;
|
||
}
|
||
return number;
|
||
}
|
||
NODE
|
||
}
|
||
|
||
echo "[pingora-direct-enable] apply=${APPLY} service=${SERVICE_NAME} template=${TEMPLATE_PATH} dropin=${DROPIN_PATH}"
|
||
|
||
if [[ "${APPLY}" != "true" ]]; then
|
||
echo "[pingora-direct-enable] 当前是 dry-run;确认 preflight 通过后追加 --apply。"
|
||
if [[ ! -f "${TEMPLATE_PATH}" ]]; then
|
||
echo "[pingora-direct-enable] dry-run 提示:当前模板不存在,--apply 会失败: ${TEMPLATE_PATH}" >&2
|
||
fi
|
||
fi
|
||
|
||
run_current_release_audit
|
||
run_preflight
|
||
run_cmd install -d -m 0755 "$(dirname "${DROPIN_PATH}")"
|
||
run_cmd install -m 0644 "${TEMPLATE_PATH}" "${DROPIN_PATH}"
|
||
run_systemctl daemon-reload
|
||
run_systemctl restart "${SERVICE_NAME}"
|
||
verify_systemd_dropin
|
||
verify_systemd_exec_start
|
||
verify_service_active_after_restart
|
||
run_direct_live_smoke_after_enable
|
||
|
||
if [[ "${STATUS_AFTER}" == "true" ]]; then
|
||
run_systemctl status "${SERVICE_NAME}" --no-pager
|
||
fi
|
||
|
||
cat <<EOF
|
||
[pingora-direct-enable] 完成。后续请确认:
|
||
- systemctl cat ${SERVICE_NAME} 包含 AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||
- systemctl show ${SERVICE_NAME} --property=ExecStart --value --no-pager 指向 current release 的 pingora-gateway
|
||
- systemctl is-active ${SERVICE_NAME} 为 active
|
||
- node ${CURRENT_RELEASE_AUDIT_SCRIPT} --release-root ${CURRENT_RELEASE_ROOT} --require-pingora-gateway --systemd-show --systemd-service ${SERVICE_NAME} 已通过
|
||
- npm run check:pingora-direct-preflight -- --env-file /etc/genarrative/pingora-gateway.env --require-live-env --systemd-cat --check-cert-readable --check-service-env-file --check-service-user-cert-readable --check-service-binary-executable --check-ports-free 已通过
|
||
- node ${DIRECT_LIVE_SCRIPT} --https-base-url ${DIRECT_HTTPS_BASE_URL:-<direct-https-base-url>} --http-base-url ${DIRECT_HTTP_BASE_URL:-<direct-http-base-url>} --host ${DIRECT_HOST:-<direct-host>} --redirect-host ${DIRECT_REDIRECT_HOST:-<direct-redirect-host>} --pingora-access-log ${DIRECT_PINGORA_ACCESS_LOG:-<pingora-access-log>} --spacetime-database ${DIRECT_SPACETIME_DATABASE:-<database>} --require-wss-upgrade --json 已通过,且 direct-access-log 结构化证据 matched=checked、missing=0、mismatches=0
|
||
EOF
|