404 lines
16 KiB
Bash
Executable File
404 lines
16 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# 在受控 Nacos 临时配置窗口内预置狗粮账号,并在任何退出路径恢复原配置。
|
||
# 本脚本不创建额度池资源;调用既有 provision-dogfood-users.sh 完成账号与额度绑定。
|
||
set -Eeuo pipefail
|
||
|
||
readonly EXPECTED_ACK='PROVISION_DOGFOOD_WITH_NACOS_TRANSACTION'
|
||
readonly DATA_ID='huijing-server-staging.yaml'
|
||
readonly NACOS_GROUP='DEFAULT_GROUP'
|
||
readonly CODE_USERNAME_OR_PASSWORD_ERROR='1002090005'
|
||
readonly CODE_PASSWORD_REGISTER_DISABLED='1002090007'
|
||
readonly CODE_DOGFOOD_SMS_DISABLED='1002090008'
|
||
readonly CODE_AD_DOGFOOD_DISABLED='1111002006'
|
||
|
||
MODE='transaction'
|
||
WATCHDOG_RECOVERY_DIR=''
|
||
if [ "${1:-}" = '--watchdog' ]; then
|
||
MODE='watchdog'
|
||
WATCHDOG_RECOVERY_DIR="${2:-}"
|
||
elif [ -n "${1:-}" ]; then
|
||
printf 'DOGFOOD_NACOS_TX_FAIL 未知参数:%s\n' "$1" >&2
|
||
exit 2
|
||
fi
|
||
|
||
DOGFOOD_PROVISION_ACK="${DOGFOOD_PROVISION_ACK:-}"
|
||
ADMIN_TOKEN_FILE="${ADMIN_TOKEN_FILE:-}"
|
||
BASE="${BASE:-http://100.64.0.7:48080}"
|
||
TENANT="${TENANT:-1}"
|
||
NACOS_BASE_URL="${NACOS_BASE_URL:-http://100.64.0.8:8848/nacos}"
|
||
NACOS_USERNAME="${NACOS_USERNAME:-nacos}"
|
||
NACOS_PASSWORD="${NACOS_PASSWORD:-}"
|
||
NACOS_ENV_FILE="${NACOS_ENV_FILE:-/root/huijing-dev.env}"
|
||
BACKEND_UNIT="${BACKEND_UNIT:-gda-staging-backend}"
|
||
PROVISION_BIN="${PROVISION_BIN:-$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/provision-dogfood-users.sh}"
|
||
CURL_BIN="${CURL_BIN:-curl}"
|
||
SYSTEMCTL_BIN="${SYSTEMCTL_BIN:-systemctl}"
|
||
SYSTEMD_RUN_BIN="${SYSTEMD_RUN_BIN:-systemd-run}"
|
||
FLOCK_BIN="${FLOCK_BIN:-flock}"
|
||
SLEEP_BIN="${SLEEP_BIN:-sleep}"
|
||
RESTART_TIMEOUT_SEC="${RESTART_TIMEOUT_SEC:-180}"
|
||
PROVISION_TTL_SEC="${PROVISION_TTL_SEC:-900}"
|
||
RUN_ID="${RUN_ID:-$(date -u +%Y%m%dT%H%M%SZ)-$$}"
|
||
EVIDENCE_DIR="${EVIDENCE_DIR:-/root/game-staging/evidence/dogfood-provision-$RUN_ID}"
|
||
LOCK_FILE="${LOCK_FILE:-/root/game-staging/locks/dogfood-provision.lock}"
|
||
EVENT_LOG=''
|
||
|
||
log() {
|
||
local line
|
||
line="[$(date -u +%Y-%m-%dT%H:%M:%SZ)] $*"
|
||
printf '%s\n' "$line"
|
||
[ -z "$EVENT_LOG" ] || printf '%s\n' "$line" >>"$EVENT_LOG"
|
||
}
|
||
die() { printf 'DOGFOOD_NACOS_TX_FAIL %s\n' "$*" >&2; exit 1; }
|
||
|
||
[[ "$RESTART_TIMEOUT_SEC" =~ ^[0-9]+$ ]] && [ "$RESTART_TIMEOUT_SEC" -ge 30 ] || \
|
||
die 'RESTART_TIMEOUT_SEC 必须是至少 30 秒的整数'
|
||
[[ "$PROVISION_TTL_SEC" =~ ^[0-9]+$ ]] && [ "$PROVISION_TTL_SEC" -ge 60 ] || \
|
||
die 'PROVISION_TTL_SEC 必须是至少 60 秒的整数'
|
||
[ "$MODE" = watchdog ] || [ "$DOGFOOD_PROVISION_ACK" = "$EXPECTED_ACK" ] || \
|
||
die "DOGFOOD_PROVISION_ACK 不匹配;必须精确确认 $EXPECTED_ACK"
|
||
[ "$MODE" = watchdog ] || [ -x "$PROVISION_BIN" ] || die "预置脚本不可执行:$PROVISION_BIN"
|
||
[ "$MODE" = watchdog ] || [ -n "$ADMIN_TOKEN_FILE" ] || die 'ADMIN_TOKEN_FILE 必填'
|
||
[ "$MODE" = watchdog ] || { [ -f "$ADMIN_TOKEN_FILE" ] && [ ! -L "$ADMIN_TOKEN_FILE" ]; } || \
|
||
die 'ADMIN_TOKEN_FILE 必须是非 symlink 普通文件'
|
||
if [ "$MODE" != watchdog ]; then
|
||
token_mode="$(stat -f '%Lp' "$ADMIN_TOKEN_FILE" 2>/dev/null || stat -c '%a' "$ADMIN_TOKEN_FILE")"
|
||
[ "$token_mode" = 600 ] || die "ADMIN_TOKEN_FILE 权限必须为 0600 actual=$token_mode"
|
||
fi
|
||
command -v python3 >/dev/null || die '缺少 python3'
|
||
python3 -c 'import yaml' >/dev/null 2>&1 || die '缺少 PyYAML,无法安全合并既有 Nacos YAML'
|
||
|
||
mkdir -p "$(dirname "$LOCK_FILE")"
|
||
exec 9>"$LOCK_FILE"
|
||
if [ "$MODE" = watchdog ]; then
|
||
"$FLOCK_BIN" -w 30 9 || die 'watchdog 无法取得预置恢复锁'
|
||
else
|
||
"$FLOCK_BIN" -n 9 || die '已有 dogfood 账号预置事务运行,拒绝并发'
|
||
fi
|
||
|
||
if [ -z "$NACOS_PASSWORD" ]; then
|
||
[ -f "$NACOS_ENV_FILE" ] || die "缺少 Nacos 凭据来源:$NACOS_ENV_FILE"
|
||
set -a
|
||
# shellcheck disable=SC1090
|
||
. "$NACOS_ENV_FILE"
|
||
set +a
|
||
NACOS_PASSWORD="${NACOS_PASSWORD:-}"
|
||
fi
|
||
[ -n "$NACOS_PASSWORD" ] || die 'Nacos 口令为空'
|
||
|
||
umask 077
|
||
if [ "$MODE" = watchdog ]; then
|
||
[ -d "$WATCHDOG_RECOVERY_DIR" ] && [ ! -L "$WATCHDOG_RECOVERY_DIR" ] || die 'watchdog recovery 目录非法'
|
||
EVIDENCE_DIR="$(dirname "$WATCHDOG_RECOVERY_DIR")"
|
||
else
|
||
[ ! -e "$EVIDENCE_DIR" ] || die "证据目录已存在,拒绝覆盖:$EVIDENCE_DIR"
|
||
mkdir -p "$EVIDENCE_DIR"
|
||
fi
|
||
chmod 700 "$EVIDENCE_DIR"
|
||
EVENT_LOG="$EVIDENCE_DIR/transaction.log"
|
||
[ "$MODE" = watchdog ] || : >"$EVENT_LOG"
|
||
chmod 600 "$EVENT_LOG"
|
||
BODY_FILE="$(mktemp)"
|
||
NACOS_PASSWORD_FILE="$(mktemp)"
|
||
NACOS_TOKEN_FILE="$(mktemp)"
|
||
printf '%s' "$NACOS_PASSWORD" >"$NACOS_PASSWORD_FILE"
|
||
chmod 600 "$NACOS_PASSWORD_FILE" "$NACOS_TOKEN_FILE"
|
||
ORIGINAL_CONFIG="$EVIDENCE_DIR/nacos-original.yaml"
|
||
TEMP_CONFIG="$EVIDENCE_DIR/nacos-temporary.yaml"
|
||
ORIGINAL_STATUS_FILE="$EVIDENCE_DIR/nacos-original.status"
|
||
SUMMARY_FILE="$EVIDENCE_DIR/transaction.status"
|
||
RECOVERY_DIR="$EVIDENCE_DIR/watchdog"
|
||
WATCHDOG_UNIT="dogfood-provision-watchdog-${RUN_ID//[^A-Za-z0-9_-]/-}"
|
||
restore_required=0
|
||
finalizing=0
|
||
watchdog_armed=0
|
||
NACOS_TOKEN=''
|
||
LAST_HTTP=''
|
||
LAST_BODY=''
|
||
|
||
cleanup_body() { rm -f "$BODY_FILE" "$NACOS_PASSWORD_FILE" "$NACOS_TOKEN_FILE"; }
|
||
|
||
request() {
|
||
local method="$1" url="$2" data="${3:-}" token="${4:-}" content_file="${5:-}"
|
||
local -a args=(-sS --connect-timeout 5 --max-time 30 -o "$BODY_FILE" -w '%{http_code}' -X "$method")
|
||
if [ -n "$token" ]; then
|
||
[ "$method" != GET ] || args+=(-G)
|
||
# token 通过 mode600 临时文件交给 curl,避免出现在进程参数或日志。
|
||
args+=(--data-urlencode "accessToken@$NACOS_TOKEN_FILE")
|
||
fi
|
||
[ -z "$data" ] || args+=(--data "$data")
|
||
[ -z "$content_file" ] || args+=(--data-urlencode "content@$content_file")
|
||
LAST_HTTP="$("$CURL_BIN" "${args[@]}" "$url" 2>/dev/null || printf '000')"
|
||
LAST_BODY="$(<"$BODY_FILE")"
|
||
}
|
||
|
||
json_value() {
|
||
local path="$1"
|
||
printf '%s' "$LAST_BODY" | python3 -c '
|
||
import json,sys
|
||
try:
|
||
value=json.load(sys.stdin)
|
||
for part in sys.argv[1].split("."):
|
||
value=value.get(part) if isinstance(value,dict) else None
|
||
if isinstance(value,bool): print("true" if value else "false")
|
||
else: print("" if value is None else value)
|
||
except Exception: print("")
|
||
' "$path"
|
||
}
|
||
|
||
nacos_login() {
|
||
# 用户名与口令分别 URL encode;响应 token 只驻内存和临时响应文件,不落 evidence。
|
||
LAST_HTTP="$("$CURL_BIN" -sS --connect-timeout 5 --max-time 30 -o "$BODY_FILE" -w '%{http_code}' \
|
||
-X POST --data-urlencode "username=$NACOS_USERNAME" --data-urlencode "password@$NACOS_PASSWORD_FILE" \
|
||
"$NACOS_BASE_URL/v1/auth/login" 2>/dev/null || printf '000')"
|
||
LAST_BODY="$(<"$BODY_FILE")"
|
||
[ "$LAST_HTTP" = 200 ] || return 1
|
||
NACOS_TOKEN="$(json_value accessToken)"
|
||
[ -n "$NACOS_TOKEN" ] || return 1
|
||
printf '%s' "$NACOS_TOKEN" >"$NACOS_TOKEN_FILE"
|
||
chmod 600 "$NACOS_TOKEN_FILE"
|
||
}
|
||
|
||
nacos_get() {
|
||
local output="$1"
|
||
request GET "$NACOS_BASE_URL/v1/cs/configs?dataId=$DATA_ID&group=$NACOS_GROUP&tenant=" '' "$NACOS_TOKEN"
|
||
# 从 curl 原始响应文件复制,保留 Nacos 配置末尾换行等字节;命令替换会吞尾换行,不能用于快照。
|
||
cp "$BODY_FILE" "$output"
|
||
chmod 600 "$output"
|
||
[ "$LAST_HTTP" = 200 ] || [ "$LAST_HTTP" = 404 ]
|
||
}
|
||
|
||
nacos_md5() {
|
||
python3 - "$1" <<'PY'
|
||
import hashlib,sys
|
||
with open(sys.argv[1],"rb") as handle:
|
||
print(hashlib.md5(handle.read()).hexdigest())
|
||
PY
|
||
}
|
||
|
||
nacos_publish() {
|
||
local content_file="$1" expected_md5="$2"
|
||
[[ "$expected_md5" =~ ^[0-9a-f]{32}$ ]] || return 1
|
||
request POST "$NACOS_BASE_URL/v1/cs/configs" \
|
||
"dataId=$DATA_ID&group=$NACOS_GROUP&tenant=&casMd5=$expected_md5" "$NACOS_TOKEN" "$content_file"
|
||
[ "$LAST_HTTP" = 200 ] && [ "$LAST_BODY" = true ]
|
||
}
|
||
|
||
verify_nacos_exact() {
|
||
local expected_file="$1" actual="$EVIDENCE_DIR/nacos-verify.tmp"
|
||
nacos_get "$actual" || return 1
|
||
[ "$LAST_HTTP" = 200 ] || return 1
|
||
cmp -s "$expected_file" "$actual"
|
||
}
|
||
|
||
restart_backend() {
|
||
"$SYSTEMCTL_BIN" restart "$BACKEND_UNIT"
|
||
local deadline=$((SECONDS + RESTART_TIMEOUT_SEC))
|
||
while [ "$SECONDS" -lt "$deadline" ]; do
|
||
request GET "$BASE/actuator/health"
|
||
if [ "$LAST_HTTP" = 200 ] && [ "$(json_value status)" = UP ]; then
|
||
return 0
|
||
fi
|
||
"$SLEEP_BIN" 2
|
||
done
|
||
return 1
|
||
}
|
||
|
||
expect_code() {
|
||
local name="$1" expected="$2" method="$3" path="$4" data="${5:-}" auth="${6:-}"
|
||
local -a args=(-sS --connect-timeout 5 --max-time 30 -o "$BODY_FILE" -w '%{http_code}' -X "$method"
|
||
-H "tenant-id: $TENANT")
|
||
[ -z "$auth" ] || args+=(-H "Authorization: Bearer $auth")
|
||
[ -z "$data" ] || args+=(-H 'Content-Type: application/json' --data "$data")
|
||
LAST_HTTP="$("$CURL_BIN" "${args[@]}" "$BASE$path" 2>/dev/null || printf '000')"
|
||
LAST_BODY="$(<"$BODY_FILE")"
|
||
local actual
|
||
actual="$(json_value code)"
|
||
if [ "$LAST_HTTP" != 200 ] || [ "$actual" != "$expected" ]; then
|
||
log "$name FAIL expected=$expected actual=${actual:-none} http=$LAST_HTTP"
|
||
return 1
|
||
fi
|
||
log "$name PASS code=$expected"
|
||
}
|
||
|
||
verify_temporary_runtime() {
|
||
# 此时还没有真实玩家 token,只校验免登录边界;资金守卫由预置脚本在首次真实登录后验证。
|
||
expect_code 'provisioning SMS still disabled' "$CODE_DOGFOOD_SMS_DISABLED" POST \
|
||
/app-api/passport/send-sms-code '{"mobile":"13800000000"}'
|
||
expect_code 'provisioning ad still disabled' "$CODE_AD_DOGFOOD_DISABLED" GET /app-api/ad/slot/list-enabled
|
||
}
|
||
|
||
verify_restored_runtime() {
|
||
local suffix="${RUN_ID//[^0-9]/}"
|
||
local username="dogfoodverify${suffix:0:15}"
|
||
local login_body="{\"username\":\"$username\",\"password\":\"DogfoodVerify1\"}"
|
||
expect_code 'password register disabled' "$CODE_PASSWORD_REGISTER_DISABLED" POST \
|
||
/app-api/passport/password-register "$login_body"
|
||
# 查无用户统一返回用户名/密码错误;若登录开关关闭会返回另一业务码。
|
||
expect_code 'password login enabled' "$CODE_USERNAME_OR_PASSWORD_ERROR" POST \
|
||
/app-api/passport/password-login "$login_body"
|
||
expect_code 'SMS disabled' "$CODE_DOGFOOD_SMS_DISABLED" POST \
|
||
/app-api/passport/send-sms-code '{"mobile":"13800000000"}'
|
||
expect_code 'ad disabled' "$CODE_AD_DOGFOOD_DISABLED" GET /app-api/ad/slot/list-enabled
|
||
}
|
||
|
||
restore_original() {
|
||
local current="$EVIDENCE_DIR/nacos-before-restore.tmp" temporary_md5
|
||
log '开始恢复原 Nacos 配置'
|
||
nacos_login || return 1
|
||
nacos_get "$current" || return 1
|
||
[ "$LAST_HTTP" = 200 ] || return 1
|
||
cmp -s "$TEMP_CONFIG" "$current" || return 1
|
||
temporary_md5="$(nacos_md5 "$TEMP_CONFIG")"
|
||
nacos_publish "$ORIGINAL_CONFIG" "$temporary_md5" || return 1
|
||
verify_nacos_exact "$ORIGINAL_CONFIG" || return 1
|
||
restart_backend || return 1
|
||
verify_restored_runtime || return 1
|
||
log '原 Nacos 配置与狗粮安全边界恢复完成'
|
||
}
|
||
|
||
arm_watchdog() {
|
||
mkdir -p "$RECOVERY_DIR"
|
||
chmod 700 "$RECOVERY_DIR"
|
||
{
|
||
printf 'schema=dogfood-provision-watchdog/1\n'
|
||
printf 'run_id=%s\n' "$RUN_ID"
|
||
printf 'ttl_sec=%s\n' "$PROVISION_TTL_SEC"
|
||
printf 'temporary_md5=%s\n' "$(nacos_md5 "$TEMP_CONFIG")"
|
||
printf 'original_md5=%s\n' "$(nacos_md5 "$ORIGINAL_CONFIG")"
|
||
} >"$RECOVERY_DIR/metadata"
|
||
: >"$RECOVERY_DIR/armed"
|
||
chmod 600 "$RECOVERY_DIR/metadata" "$RECOVERY_DIR/armed"
|
||
if ! "$SYSTEMD_RUN_BIN" --quiet --collect --unit="$WATCHDOG_UNIT" \
|
||
--on-active="${PROVISION_TTL_SEC}s" --property=Type=oneshot \
|
||
--property=Restart=on-failure --property=RestartSec=15s \
|
||
/bin/bash "$(realpath "${BASH_SOURCE[0]}")" --watchdog "$RECOVERY_DIR"; then
|
||
rm -f "$RECOVERY_DIR/armed"
|
||
return 1
|
||
fi
|
||
watchdog_armed=1
|
||
log "独立恢复 watchdog 已注册 unit=$WATCHDOG_UNIT ttl=${PROVISION_TTL_SEC}s"
|
||
}
|
||
|
||
disarm_watchdog() {
|
||
[ "$watchdog_armed" -eq 1 ] || return 0
|
||
rm -f "$RECOVERY_DIR/armed"
|
||
"$SYSTEMCTL_BIN" stop "$WATCHDOG_UNIT.timer" "$WATCHDOG_UNIT.service" >/dev/null 2>&1 || true
|
||
printf 'disarmed_at=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >"$RECOVERY_DIR/disarmed"
|
||
chmod 600 "$RECOVERY_DIR/disarmed"
|
||
watchdog_armed=0
|
||
}
|
||
|
||
if [ "$MODE" = watchdog ]; then
|
||
EVENT_LOG="$EVIDENCE_DIR/watchdog.log"
|
||
touch "$EVENT_LOG"
|
||
chmod 600 "$EVENT_LOG"
|
||
[ -f "$RECOVERY_DIR/armed" ] || {
|
||
log 'watchdog 已解除,无需恢复'
|
||
cleanup_body
|
||
exit 0
|
||
}
|
||
log 'watchdog TTL 到期,开始独立恢复 Nacos 安全配置'
|
||
if restore_original; then
|
||
rm -f "$RECOVERY_DIR/armed"
|
||
printf 'WATCHDOG_RESTORE=PASS at=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >"$RECOVERY_DIR/watchdog.status"
|
||
chmod 600 "$RECOVERY_DIR/watchdog.status"
|
||
cleanup_body
|
||
exit 0
|
||
fi
|
||
printf 'WATCHDOG_RESTORE=FAILED at=%s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" >"$RECOVERY_DIR/watchdog.status"
|
||
chmod 600 "$RECOVERY_DIR/watchdog.status"
|
||
cleanup_body
|
||
die "watchdog 恢复失败,保留 armed 标记等待人工处置:$RECOVERY_DIR"
|
||
fi
|
||
|
||
finalize() {
|
||
local main_rc=$? restore_rc=0
|
||
[ "$finalizing" -eq 0 ] || return
|
||
finalizing=1
|
||
trap - EXIT INT TERM
|
||
set +e
|
||
if [ "$restore_required" -eq 1 ]; then
|
||
restore_original
|
||
restore_rc=$?
|
||
fi
|
||
cleanup_body
|
||
if [ "$restore_rc" -ne 0 ]; then
|
||
printf 'restore_failed main_rc=%s restore_rc=%s evidence=%s\n' "$main_rc" "$restore_rc" "$EVIDENCE_DIR" >"$SUMMARY_FILE"
|
||
chmod 600 "$SUMMARY_FILE"
|
||
printf 'DOGFOOD_NACOS_TX_RESTORE_FAIL evidence=%s\n' "$EVIDENCE_DIR" >&2
|
||
exit 70
|
||
fi
|
||
disarm_watchdog
|
||
if [ "$main_rc" -ne 0 ]; then
|
||
printf 'provision_failed rc=%s restored=true evidence=%s\n' "$main_rc" "$EVIDENCE_DIR" >"$SUMMARY_FILE"
|
||
chmod 600 "$SUMMARY_FILE"
|
||
printf 'DOGFOOD_NACOS_TX_FAIL rc=%s restored=true evidence=%s\n' "$main_rc" "$EVIDENCE_DIR" >&2
|
||
exit "$main_rc"
|
||
fi
|
||
printf 'pass restored=true evidence=%s\n' "$EVIDENCE_DIR" >"$SUMMARY_FILE"
|
||
chmod 600 "$SUMMARY_FILE"
|
||
printf 'DOGFOOD_NACOS_TX_PASS restored=true evidence=%s\n' "$EVIDENCE_DIR"
|
||
}
|
||
trap finalize EXIT
|
||
trap 'exit 130' INT
|
||
trap 'exit 143' TERM
|
||
|
||
log "开始狗粮账号预置配置事务 runId=$RUN_ID"
|
||
nacos_login || die 'Nacos 登录失败'
|
||
nacos_get "$ORIGINAL_CONFIG" || die "读取 $DATA_ID 失败 http=$LAST_HTTP"
|
||
printf '%s\n' "$LAST_HTTP" >"$ORIGINAL_STATUS_FILE"
|
||
chmod 600 "$ORIGINAL_STATUS_FILE"
|
||
[ "$LAST_HTTP" = 200 ] || die 'Nacos dataId 不存在,无法执行内容 CAS;拒绝创建临时配置'
|
||
|
||
# 在原 YAML 上只覆盖预置窗口所需键;原文始终单独留证并在 EXIT trap 逐字恢复。
|
||
PROVISION_TTL_SEC="$PROVISION_TTL_SEC" python3 - "$ORIGINAL_CONFIG" "$TEMP_CONFIG" <<'PY'
|
||
import datetime,os,sys,yaml
|
||
source,target=sys.argv[1:]
|
||
with open(source,encoding="utf-8") as f:
|
||
doc=yaml.safe_load(f) or {}
|
||
if not isinstance(doc,dict):
|
||
raise SystemExit("Nacos staging 配置顶层必须是 YAML object")
|
||
# 若历史配置使用过 dotted key,先移除同义键,避免 Spring 扁平化后与嵌套键冲突;原文仍会逐字恢复。
|
||
for key in (
|
||
"huijing.dogfood.enabled",
|
||
"huijing.dogfood.provisioning-enabled",
|
||
"huijing.dogfood.provisioning-expires-at",
|
||
"huijing.dogfood.provisioning-run-id",
|
||
"wanxiang.passport.password-register-enabled",
|
||
):
|
||
doc.pop(key,None)
|
||
huijing=doc.setdefault("huijing",{})
|
||
if not isinstance(huijing,dict): raise SystemExit("huijing 必须是 object")
|
||
dogfood=huijing.setdefault("dogfood",{})
|
||
if not isinstance(dogfood,dict): raise SystemExit("huijing.dogfood 必须是 object")
|
||
dogfood["enabled"]=True
|
||
dogfood["provisioning-enabled"]=True
|
||
dogfood["provisioning-run-id"]=os.environ["RUN_ID"]
|
||
expires_at=datetime.datetime.now(datetime.timezone.utc)+datetime.timedelta(seconds=int(os.environ["PROVISION_TTL_SEC"]))
|
||
dogfood["provisioning-expires-at"]=expires_at.isoformat().replace("+00:00","Z")
|
||
wanxiang=doc.setdefault("wanxiang",{})
|
||
if not isinstance(wanxiang,dict): raise SystemExit("wanxiang 必须是 object")
|
||
passport=wanxiang.setdefault("passport",{})
|
||
if not isinstance(passport,dict): raise SystemExit("wanxiang.passport 必须是 object")
|
||
passport["password-register-enabled"]=True
|
||
with open(target,"w",encoding="utf-8") as f:
|
||
yaml.safe_dump(doc,f,allow_unicode=True,sort_keys=False)
|
||
PY
|
||
chmod 600 "$TEMP_CONFIG"
|
||
|
||
arm_watchdog || die '无法注册独立恢复 watchdog,未修改 Nacos'
|
||
original_md5="$(nacos_md5 "$ORIGINAL_CONFIG")"
|
||
nacos_publish "$TEMP_CONFIG" "$original_md5" || die "发布临时 Nacos 配置 CAS 失败 http=$LAST_HTTP"
|
||
restore_required=1
|
||
verify_nacos_exact "$TEMP_CONFIG" || die '临时 Nacos 配置回读不一致'
|
||
restart_backend || die '临时配置发布后 backend 未恢复健康'
|
||
verify_temporary_runtime || die '窄 provisioning 开关未生效或安全守卫被关闭'
|
||
|
||
log '临时配置已生效,执行既有账号预置脚本'
|
||
env -u ADMIN_USERNAME -u ADMIN_PASSWORD \
|
||
PROVISION_ACK='PROVISION_DOGFOOD_40_USERS_WITH_TEMP_CONFIG' DOGFOOD_PROVISIONING_MODE=narrow \
|
||
ADMIN_TOKEN_FILE="$ADMIN_TOKEN_FILE" "$PROVISION_BIN" >"$EVIDENCE_DIR/provision.log" 2>&1
|
||
chmod 600 "$EVIDENCE_DIR/provision.log"
|
||
log '账号预置脚本完成,退出时恢复原配置'
|