Files
Chan/live/deploy/dryrun.sh
T

106 lines
5.1 KiB
Bash
Executable File
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
# 空跑验全链:真连交易所读规则/持仓,**不下任何真单**。
#
# 上真单之前必须过这一步。它验的是那些"上线才会暴露、且暴露方式是花钱"的
# 环节:密钥能不能用、IP 白名单对不对、时钟同不同步、搬运通不通、
# 数量与价位取整合不合交易所规则。
set -euo pipefail
APP=/opt/chan
CONF=/etc/chan-live/live.env
STATE=/var/lib/chan-live
USER_NAME=chan
SECS="${SECS:-90}"
die() { echo "⛔ $*" >&2; exit 1; }
ok() { echo " ✓ $*"; }
[[ $EUID -eq 0 ]] || die "要 rootsudo $0"
[[ -f "$CONF" ]] || die "缺 $CONF,先跑 install.sh"
set -a; . "$CONF"; set +a
echo "── 1. 配置自检 ──"
for v in BITGET_API_KEY BITGET_API_SECRET BITGET_PASSPHRASE SHIP_FROM; do
[[ -n "${!v:-}" ]] || die "$CONF$v 还是空的"
done
ok "密钥三项与 SHIP_FROM 都已填"
[[ "$LIVE_HOME" != /opt/chan* ]] || die "LIVE_HOME 不能指到仓库里(会被 git 清掉)"
ok "LIVE_HOME=$LIVE_HOME 在仓库外"
echo "── 2. 时钟 ──"
# staleness 闸靠两机时钟一致才有意义。这里只能验本机;跨机偏差由
# ship_signals 在收到信号时报「时间倒流」
if command -v chronyc >/dev/null; then
chronyc tracking | grep -E "Reference ID|System time|Leap status" | sed 's/^/ /'
src="$(chronyc tracking | awk '/Reference ID/{print $NF}')"
[[ "$src" != "()" && -n "$src" ]] || die "chrony 还没同步上,等一会再跑"
ok "chrony 已同步"
else
die "没装 chrony。staleness 闸不可信,先 apt install chrony"
fi
echo "── 3. 出口 IP 是否在白名单内 ──"
myip="$(curl -s --max-time 10 https://api.ipify.org || true)"
[[ -n "$myip" ]] && echo " 本机出口 IP$myip" || echo " ⚠ 取不到出口 IP"
echo " 对照 Bitget 后台该 key 的 IP 白名单,不一致下面会报 40018 之类"
echo "── 4. 能否 ssh 到采集机 ──"
# 不能用 ssh <host> 'echo ok' 来试:采集机那侧的 authorized_keys 用了强制命令
# (把这把 key 锁成只能跑 tail,拿不到 shell),任何请求都会变成 tail -F,
# 而它**永不返回**——ConnectTimeout 只管建连不管命令时长,测试会永久挂住。
# 所以照 ship_signals 的真实用法读流:tail -c +0 会先把整个文件吐出来,
# 数一下就等于对端总线的条数,之后它挂着等新内容,由 timeout 收掉。
rb="${SHIP_REMOTE_BUS:-\$HOME/chan-live/state/signals_live.jsonl}"
err="$(mktemp)"; outf="$(mktemp)"
# timeout 要套在 sudo **里面**:套外面时 SIGTERM 只到 sudo,未必传给 ssh
# 于是该被收掉的 tail 会继续挂着
sudo -u "$USER_NAME" timeout 12 ssh -T -o BatchMode=yes -o ConnectTimeout=10 \
"$SHIP_FROM" "tail -c +0 -F $rb" >"$outf" 2>"$err" || true
n="$(wc -l < "$outf")"
if grep -qi "Host key verification failed" "$err"; then
fp="(在采集机上跑 ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub 拿)"
rm -f "$err" "$outf"
die "主机指纹没确认过。这不是 key 的问题,装 key 也修不了。
$USER_NAME 的 known_hosts 是空的,而 BatchMode=yes 不允许交互确认。
**不要**用 StrictHostKeyChecking=no 糊过去,那等于放弃中间人防护。
正确做法:在采集机上读出权威指纹 $fp
再在这台上写入并核对:
sudo -u $USER_NAME ssh-keyscan -t ed25519 <采集机IP> \\
| sudo -u $USER_NAME tee -a $STATE/home/.ssh/known_hosts
sudo -u $USER_NAME ssh-keygen -lf $STATE/home/.ssh/known_hosts"
elif grep -qiE "Permission denied|publickey" "$err"; then
rm -f "$err" "$outf"
die "认证被拒。指纹是通的,是 key 没装到采集机上:
sudo -u $USER_NAME ssh-keygen -t ed25519 -N '' -f $STATE/home/.ssh/id_ed25519
再把 $STATE/home/.ssh/id_ed25519.pub 加到采集机的 authorized_keys"
elif [[ -s "$err" ]] && ! grep -q "^" "$outf" 2>/dev/null; then
msg="$(head -3 "$err")"; rm -f "$err" "$outf"
die "ssh $SHIP_FROM 不通:$msg"
else
ok "ssh $SHIP_FROM 通"
echo " 对端总线现有 $n 条信号"
[[ "$n" -gt 0 ]] || echo " ⚠ 对端总线是空的。信号 6.8 个/天,刚重启过就是空的很正常;但要确认采集机接了总线"
rm -f "$err" "$outf"
fi
echo "── 5. 执行器空跑 ${SECS}s(真连交易所,不下单)──"
# --dry-run 下 Bitget 客户端只读不写:合约规则、持仓、费率照查,
# 下单一律只打印。所以这一步会真实验到密钥与白名单
# 让 chan 自己 source 配置($CONF 是 640 root:chan,它读得到)。
# 不用 `env "$(grep ...)"` 那种拼法:值里有空格就会被切开
set +e
sudo -u "$USER_NAME" bash -c \
"set -a; . '$CONF'; set +a; exec timeout $SECS \
'$APP/.venv/bin/python' '$APP/live/live_exec.py' --dry-run"
rc=$?
set -e
# timeout 到点是 124,属于预期
[[ $rc -eq 124 || $rc -eq 0 ]] || die "空跑退出码 $rc,看上面报错"
ok "空跑没有报错退出"
echo
echo "空跑过了。真跑:"
echo " sudo systemctl enable --now chan-live-ship chan-live-exec"
echo " $APP/live/deploy/status.sh"