Support up to 3 strategy slots on one host with auto ports.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
// 默认槽位 1 模板;安装/更新时由 deploy/lib/common.sh#write_ecosystem_config 按目录重写。
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
|
||||
@@ -15,6 +15,7 @@ TZ_NAME="${EHS_TZ:-Asia/Shanghai}"
|
||||
NODE_MAJOR="${NODE_MAJOR:-20}"
|
||||
PM2_APP_NAME="${PM2_APP_NAME:-eth-hedge-api}"
|
||||
API_PORT="${API_PORT:-5155}"
|
||||
INSTANCE_SLOT="${INSTANCE_SLOT:-1}"
|
||||
|
||||
LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DEPLOY_DIR="$(cd "${LIB_DIR}/.." && pwd)"
|
||||
@@ -28,6 +29,167 @@ die() {
|
||||
exit 1
|
||||
}
|
||||
|
||||
# ---------- 同机多套槽位(1/2/3) ----------
|
||||
|
||||
infer_slot_from_root() {
|
||||
local root="${1%/}"
|
||||
case "${root}" in
|
||||
*/eth_hedge_sim_2) echo 2 ;;
|
||||
*/eth_hedge_sim_3) echo 3 ;;
|
||||
*) echo 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 设置 INSTANCE_SLOT / INSTALL_ROOT / API_PORT / PM2_APP_NAME
|
||||
resolve_slot() {
|
||||
local slot="${1:-${INSTANCE_SLOT:-1}}"
|
||||
case "${slot}" in
|
||||
1|2|3) ;;
|
||||
*) die "无效槽位: ${slot}(仅支持 1/2/3)" ;;
|
||||
esac
|
||||
INSTANCE_SLOT="${slot}"
|
||||
case "${slot}" in
|
||||
1)
|
||||
INSTALL_ROOT="/opt/eth_hedge_sim"
|
||||
API_PORT="5155"
|
||||
PM2_APP_NAME="eth-hedge-api"
|
||||
;;
|
||||
2)
|
||||
INSTALL_ROOT="/opt/eth_hedge_sim_2"
|
||||
API_PORT="5156"
|
||||
PM2_APP_NAME="eth-hedge-api-2"
|
||||
;;
|
||||
3)
|
||||
INSTALL_ROOT="/opt/eth_hedge_sim_3"
|
||||
API_PORT="5157"
|
||||
PM2_APP_NAME="eth-hedge-api-3"
|
||||
;;
|
||||
esac
|
||||
export INSTANCE_SLOT INSTALL_ROOT API_PORT PM2_APP_NAME
|
||||
}
|
||||
|
||||
# 按实际仓库目录对齐槽位(pull/update 时以目录为准)
|
||||
apply_slot_for_root() {
|
||||
local root="${1%/}"
|
||||
[[ -n "${root}" ]] || die "apply_slot_for_root: 空目录"
|
||||
resolve_slot "$(infer_slot_from_root "${root}")"
|
||||
INSTALL_ROOT="${root}"
|
||||
REPO_ROOT="${root}"
|
||||
# 已有 .env 时保留用户改过的端口
|
||||
if [[ -f "${root}/.env" ]]; then
|
||||
local p=""
|
||||
p="$(grep -E '^API_PORT=' "${root}/.env" 2>/dev/null | head -n1 | cut -d= -f2- | tr -d '\r' || true)"
|
||||
if [[ -n "${p}" && "${p}" =~ ^[0-9]+$ ]]; then
|
||||
API_PORT="${p}"
|
||||
fi
|
||||
fi
|
||||
export INSTANCE_SLOT INSTALL_ROOT API_PORT PM2_APP_NAME REPO_ROOT
|
||||
}
|
||||
|
||||
is_allowed_install_root() {
|
||||
local root="${1%/}"
|
||||
case "${root}" in
|
||||
/opt/eth_hedge_sim|/opt/eth_hedge_sim_2|/opt/eth_hedge_sim_3) return 0 ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
port_is_listening() {
|
||||
local port="$1"
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
ss -ltn 2>/dev/null | grep -qE ":${port}[[:space:]]" && return 0
|
||||
fi
|
||||
if command -v lsof >/dev/null 2>&1; then
|
||||
lsof -iTCP:"${port}" -sTCP:LISTEN >/dev/null 2>&1 && return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# 全新安装前:端口已被占用且不是本槽位 PM2 → 失败
|
||||
assert_port_free_for_install() {
|
||||
local port="${1:-${API_PORT}}"
|
||||
local name="${2:-${PM2_APP_NAME}}"
|
||||
if command -v pm2 >/dev/null 2>&1; then
|
||||
if pm2 describe "${name}" >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
if port_is_listening "${port}"; then
|
||||
die "端口 ${port} 已被占用(槽位 ${INSTANCE_SLOT} / ${name})。请释放端口或换槽位"
|
||||
fi
|
||||
}
|
||||
|
||||
write_ecosystem_config() {
|
||||
local root="${1:-${INSTALL_ROOT}}"
|
||||
local name="${2:-${PM2_APP_NAME}}"
|
||||
local port="${3:-${API_PORT}}"
|
||||
local out="${root}/deploy/ecosystem.config.cjs"
|
||||
mkdir -p "${root}/deploy"
|
||||
cat >"${out}" <<EOF
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: '${name}',
|
||||
cwd: '${root}/backend',
|
||||
script: '${root}/.venv/bin/uvicorn',
|
||||
args: 'app.main:app --host 0.0.0.0 --port ${port}',
|
||||
interpreter: 'none',
|
||||
env: {
|
||||
// MODE 以仓库根 .env 为准(设置页可切 SIM/LIVE),勿在此硬编码覆盖
|
||||
ENV_NAME: 'test',
|
||||
TZ: 'Asia/Shanghai',
|
||||
},
|
||||
// 密钥与本地配置一律读 ${root}/.env(勿写进本文件)
|
||||
},
|
||||
],
|
||||
};
|
||||
EOF
|
||||
log "已写入 PM2: name=${name} port=${port} → ${out}"
|
||||
}
|
||||
|
||||
random_auth_secret() {
|
||||
if command -v openssl >/dev/null 2>&1; then
|
||||
openssl rand -hex 24
|
||||
return 0
|
||||
fi
|
||||
head -c 32 /dev/urandom 2>/dev/null | od -An -tx1 | tr -d ' \n' | head -c 48
|
||||
echo ""
|
||||
}
|
||||
|
||||
# SKIP_SLOT_PROMPT=1 时用环境变量 INSTANCE_SLOT(默认 1),供「全部更新」等非交互调用
|
||||
prompt_instance_slot() {
|
||||
local line=""
|
||||
local slot=""
|
||||
if [[ "${SKIP_SLOT_PROMPT:-0}" == "1" ]]; then
|
||||
resolve_slot "${INSTANCE_SLOT:-1}"
|
||||
log "槽位 ${INSTANCE_SLOT}: ${INSTALL_ROOT} port=${API_PORT} pm2=${PM2_APP_NAME}"
|
||||
return 0
|
||||
fi
|
||||
echo ""
|
||||
echo "策略机槽位(同机最多 3 套,互不影响):"
|
||||
echo " 1 → /opt/eth_hedge_sim :5155 eth-hedge-api"
|
||||
echo " 2 → /opt/eth_hedge_sim_2 :5156 eth-hedge-api-2"
|
||||
echo " 3 → /opt/eth_hedge_sim_3 :5157 eth-hedge-api-3"
|
||||
cm_read line "请选择槽位 [1/2/3,默认1]: "
|
||||
slot="${line:-1}"
|
||||
resolve_slot "${slot}"
|
||||
log "槽位 ${INSTANCE_SLOT}: ${INSTALL_ROOT} port=${API_PORT} pm2=${PM2_APP_NAME}"
|
||||
}
|
||||
|
||||
list_installed_slots() {
|
||||
local s root
|
||||
for s in 1 2 3; do
|
||||
case "${s}" in
|
||||
1) root="/opt/eth_hedge_sim" ;;
|
||||
2) root="/opt/eth_hedge_sim_2" ;;
|
||||
3) root="/opt/eth_hedge_sim_3" ;;
|
||||
esac
|
||||
if repo_ready "${root}"; then
|
||||
echo "${s}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
require_root() {
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
die "请使用 root 执行(推荐: sudo -i 后运行)"
|
||||
@@ -360,11 +522,13 @@ print_post_install_guide() {
|
||||
echo ""
|
||||
echo "══════════════════════════════════════"
|
||||
echo " 比特骆驼自动化对冲系统 部署完成"
|
||||
echo " 槽位: ${INSTANCE_SLOT:-1}"
|
||||
echo " 目录: ${INSTALL_ROOT}"
|
||||
echo " 本机: http://${ip}:${API_PORT}/health"
|
||||
echo " 进程: pm2 status → ${PM2_APP_NAME}"
|
||||
echo " 管理: bash ${INSTALL_ROOT}/deploy/manage.sh"
|
||||
echo " 配置: ${INSTALL_ROOT}/.env"
|
||||
echo " 同机多套: 菜单选槽位 2/3;实盘请只用槽位 1"
|
||||
echo "══════════════════════════════════════"
|
||||
echo ""
|
||||
}
|
||||
|
||||
+18
-6
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# deploy/lib/install.sh — 一键部署策略机
|
||||
# deploy/lib/install.sh — 一键部署策略机(支持槽位 1/2/3)
|
||||
set -e
|
||||
set -u
|
||||
if [ -n "${BASH_VERSION:-}" ]; then
|
||||
@@ -13,10 +13,12 @@ source "${LIB_DIR}/common.sh"
|
||||
run_pipeline() {
|
||||
local root="$1"
|
||||
REPO_ROOT="${root}"
|
||||
step "构建并启动策略机 (pull_and_restart.sh)"
|
||||
INSTALL_ROOT="${root}"
|
||||
apply_slot_for_root "${root}"
|
||||
step "构建并启动策略机 (pull_and_restart.sh) slot=${INSTANCE_SLOT}"
|
||||
bash "${REPO_ROOT}/deploy/pull_and_restart.sh"
|
||||
pm2_save_startup
|
||||
verify_health || true
|
||||
verify_health "${API_PORT}" || true
|
||||
print_post_install_guide
|
||||
}
|
||||
|
||||
@@ -24,7 +26,8 @@ install_fresh() {
|
||||
require_root
|
||||
step "一键部署策略机 — 环境检测与依赖"
|
||||
ensure_system_deps
|
||||
step "克隆仓库 → ${INSTALL_ROOT}"
|
||||
assert_port_free_for_install "${API_PORT}" "${PM2_APP_NAME}"
|
||||
step "克隆仓库 → ${INSTALL_ROOT}(槽位 ${INSTANCE_SLOT} / :${API_PORT})"
|
||||
if [[ -d "${INSTALL_ROOT}" ]]; then
|
||||
die "目录已存在: ${INSTALL_ROOT},请先卸载或选修复"
|
||||
fi
|
||||
@@ -40,13 +43,13 @@ install_repair() {
|
||||
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
||||
die "未找到安装目录 ${INSTALL_ROOT}"
|
||||
fi
|
||||
step "修复环境(保留 .env 与数据库)"
|
||||
step "修复环境(保留 .env 与数据库) slot=${INSTANCE_SLOT}"
|
||||
run_pipeline "${REPO_ROOT}"
|
||||
}
|
||||
|
||||
handle_existing() {
|
||||
echo ""
|
||||
echo "检测到已部署: ${INSTALL_ROOT}"
|
||||
echo "检测到已部署: ${INSTALL_ROOT}(槽位 ${INSTANCE_SLOT})"
|
||||
echo " a) 取消"
|
||||
echo " b) 修复/重装环境(保留 .env 与 SQLite)"
|
||||
local choice=""
|
||||
@@ -59,6 +62,15 @@ handle_existing() {
|
||||
|
||||
main_install() {
|
||||
require_root
|
||||
# manage.sh 已 prompt;直接调用时按 INSTANCE_SLOT / INSTALL_ROOT 对齐
|
||||
if [[ "${INSTALL_ROOT}" == "/opt/eth_hedge_sim_2" ]]; then
|
||||
resolve_slot 2
|
||||
elif [[ "${INSTALL_ROOT}" == "/opt/eth_hedge_sim_3" ]]; then
|
||||
resolve_slot 3
|
||||
else
|
||||
resolve_slot "${INSTANCE_SLOT:-1}"
|
||||
fi
|
||||
|
||||
if repo_ready "${INSTALL_ROOT}"; then
|
||||
handle_existing
|
||||
else
|
||||
|
||||
+27
-24
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# deploy/lib/uninstall.sh — 一键卸载(仅本项目 PM2,删除 /opt 安装目录)
|
||||
# deploy/lib/uninstall.sh — 一键卸载指定槽位(仅该槽位 PM2 + 目录)
|
||||
set -e
|
||||
set -u
|
||||
if [ -n "${BASH_VERSION:-}" ]; then
|
||||
@@ -13,6 +13,8 @@ source "${LIB_DIR}/common.sh"
|
||||
main_uninstall() {
|
||||
require_root
|
||||
|
||||
resolve_slot "${INSTANCE_SLOT:-1}"
|
||||
|
||||
local root=""
|
||||
if ! root="$(resolve_repo_root)"; then
|
||||
if [[ -d "${INSTALL_ROOT}" ]]; then
|
||||
@@ -22,13 +24,15 @@ main_uninstall() {
|
||||
fi
|
||||
fi
|
||||
REPO_ROOT="${root}"
|
||||
INSTALL_ROOT="${root}"
|
||||
apply_slot_for_root "${root}"
|
||||
|
||||
echo ""
|
||||
echo "将卸载 比特骆驼自动化对冲系统 (eth_hedge_sim):"
|
||||
echo "将卸载 比特骆驼自动化对冲系统 槽位 ${INSTANCE_SLOT}:"
|
||||
echo " - 停止并删除 PM2 进程: ${PM2_APP_NAME}"
|
||||
echo " - 删除安装目录: ${INSTALL_ROOT}"
|
||||
echo " - 备份 .env / 数据库到 ${BACKUP_ROOT}"
|
||||
echo " - 不影响其它 PM2 应用 / 不卸载系统 Python、Node、PM2"
|
||||
echo " - 不影响其它槽位 / 其它 PM2 / 系统 Python、Node、PM2"
|
||||
echo ""
|
||||
if ! confirm_yes "确认卸载并删除 ${INSTALL_ROOT}?"; then
|
||||
log "已取消卸载"
|
||||
@@ -37,7 +41,7 @@ main_uninstall() {
|
||||
|
||||
local stamp backup_dir
|
||||
stamp="$(TZ="${TZ_NAME}" date +%Y%m%d-%H%M%S)"
|
||||
backup_dir="${BACKUP_ROOT}/pre-uninstall-${stamp}"
|
||||
backup_dir="${BACKUP_ROOT}/pre-uninstall-slot${INSTANCE_SLOT}-${stamp}"
|
||||
mkdir -p "${backup_dir}"
|
||||
|
||||
step "备份配置与数据"
|
||||
@@ -49,7 +53,9 @@ main_uninstall() {
|
||||
fi
|
||||
{
|
||||
echo "created_at=${stamp}"
|
||||
echo "instance_slot=${INSTANCE_SLOT}"
|
||||
echo "install_root=${INSTALL_ROOT}"
|
||||
echo "api_port=${API_PORT}"
|
||||
echo "pm2_app=${PM2_APP_NAME}"
|
||||
echo "action=rm_rf_install_root"
|
||||
} >"${backup_dir}/uninstall.manifest"
|
||||
@@ -60,28 +66,23 @@ main_uninstall() {
|
||||
|
||||
step "删除安装目录 ${INSTALL_ROOT}"
|
||||
if [[ -d "${INSTALL_ROOT}" ]]; then
|
||||
# 安全:只允许删除约定安装路径(默认 /opt/eth_hedge_sim)
|
||||
case "${INSTALL_ROOT}" in
|
||||
/opt/eth_hedge_sim|/opt/eth_hedge_sim/)
|
||||
rm -rf "${INSTALL_ROOT}"
|
||||
log "已删除: ${INSTALL_ROOT}"
|
||||
;;
|
||||
*)
|
||||
if [[ "${ALLOW_UNSAFE_UNINSTALL:-}" == "1" ]]; then
|
||||
rm -rf "${INSTALL_ROOT}"
|
||||
log "已删除(ALLOW_UNSAFE_UNINSTALL=1): ${INSTALL_ROOT}"
|
||||
else
|
||||
die "拒绝删除非默认路径 ${INSTALL_ROOT};若确认,设置 ALLOW_UNSAFE_UNINSTALL=1"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
if is_allowed_install_root "${INSTALL_ROOT}"; then
|
||||
rm -rf "${INSTALL_ROOT}"
|
||||
log "已删除: ${INSTALL_ROOT}"
|
||||
elif [[ "${ALLOW_UNSAFE_UNINSTALL:-}" == "1" ]]; then
|
||||
rm -rf "${INSTALL_ROOT}"
|
||||
log "已删除(ALLOW_UNSAFE_UNINSTALL=1): ${INSTALL_ROOT}"
|
||||
else
|
||||
die "拒绝删除非约定路径 ${INSTALL_ROOT};允许: /opt/eth_hedge_sim[_2|_3];或 ALLOW_UNSAFE_UNINSTALL=1"
|
||||
fi
|
||||
else
|
||||
log "安装目录不存在,跳过删除"
|
||||
fi
|
||||
|
||||
# 清理历史「移走未删」残留
|
||||
local leftover
|
||||
for leftover in /opt/eth_hedge_sim.removed.* /opt/eth_hedge_sim.old.*; do
|
||||
# 清理历史「移走未删」残留(仅当前槽位前缀)
|
||||
local leftover base
|
||||
base="${INSTALL_ROOT}"
|
||||
for leftover in "${base}.removed."* "${base}.old."*; do
|
||||
if [[ -e "${leftover}" ]]; then
|
||||
rm -rf "${leftover}"
|
||||
log "已清理残留: ${leftover}"
|
||||
@@ -90,11 +91,13 @@ main_uninstall() {
|
||||
|
||||
echo ""
|
||||
echo "卸载完成."
|
||||
echo " 槽位: ${INSTANCE_SLOT}"
|
||||
echo " 配置/数据备份: ${backup_dir}"
|
||||
echo " 安装目录已删除: ${INSTALL_ROOT}"
|
||||
echo ""
|
||||
echo "重新部署:"
|
||||
echo " curl -fsSL https://git.bz121.com/dekun/eth_hedge_sim/raw/branch/main/deploy/manage.sh | bash"
|
||||
echo "重新部署该槽位:"
|
||||
echo " bash /opt/eth_hedge_sim/deploy/manage.sh # 选 1 → 槽位 ${INSTANCE_SLOT}"
|
||||
echo " 或: INSTANCE_SLOT=${INSTANCE_SLOT} SKIP_SLOT_PROMPT=1 bash …/deploy/lib/install.sh"
|
||||
}
|
||||
|
||||
main_uninstall "$@"
|
||||
|
||||
+42
-6
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
# deploy/lib/update.sh — 更新(仅 git pull,禁止 scp)
|
||||
# deploy/lib/update.sh — 更新(仅 git pull,禁止 scp);支持单槽位或全部串行
|
||||
set -e
|
||||
set -u
|
||||
if [ -n "${BASH_VERSION:-}" ]; then
|
||||
@@ -10,22 +10,58 @@ LIB_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=common.sh
|
||||
source "${LIB_DIR}/common.sh"
|
||||
|
||||
update_one_slot() {
|
||||
local slot="$1"
|
||||
resolve_slot "${slot}"
|
||||
if ! repo_ready "${INSTALL_ROOT}"; then
|
||||
log "槽位 ${slot} 未安装(${INSTALL_ROOT}),跳过"
|
||||
return 0
|
||||
fi
|
||||
step "更新槽位 ${slot}: ${INSTALL_ROOT} :${API_PORT} ${PM2_APP_NAME}"
|
||||
ensure_system_deps
|
||||
bash "${INSTALL_ROOT}/deploy/pull_and_restart.sh"
|
||||
verify_health "${API_PORT}" || true
|
||||
log "槽位 ${slot} 更新完成"
|
||||
}
|
||||
|
||||
update_all_slots() {
|
||||
local s
|
||||
local any=0
|
||||
step "串行更新全部已安装策略机槽位(避免同机并行 npm build)"
|
||||
for s in $(list_installed_slots); do
|
||||
any=1
|
||||
update_one_slot "${s}"
|
||||
done
|
||||
if [[ "${any}" -eq 0 ]]; then
|
||||
die "未找到已安装的策略机(槽位 1/2/3)"
|
||||
fi
|
||||
echo ""
|
||||
log "全部槽位更新完成"
|
||||
}
|
||||
|
||||
main_update() {
|
||||
require_root
|
||||
local mode="${EHS_UPDATE_MODE:-one}"
|
||||
if [[ "${mode}" == "all" ]]; then
|
||||
update_all_slots
|
||||
return 0
|
||||
fi
|
||||
|
||||
resolve_slot "${INSTANCE_SLOT:-1}"
|
||||
if ! REPO_ROOT="$(resolve_repo_root)"; then
|
||||
die "未找到安装目录 ${INSTALL_ROOT},请先执行「1) 一键部署策略机」"
|
||||
die "未找到安装目录 ${INSTALL_ROOT},请先执行「1) 一键部署策略机」并选择该槽位"
|
||||
fi
|
||||
if ! repo_ready "${REPO_ROOT}"; then
|
||||
die "安装不完整,请先执行「1) 一键部署策略机」"
|
||||
die "安装不完整: ${REPO_ROOT}"
|
||||
fi
|
||||
|
||||
step "更新 — 环境检测 (缺则装,有则跳过)"
|
||||
ensure_system_deps
|
||||
step "更新 比特骆驼自动化对冲系统 (git pull + 构建 + pm2 reload)"
|
||||
step "更新槽位 ${INSTANCE_SLOT} (git pull + 构建 + pm2 reload)"
|
||||
bash "${REPO_ROOT}/deploy/pull_and_restart.sh"
|
||||
verify_health || true
|
||||
verify_health "${API_PORT}" || true
|
||||
echo ""
|
||||
log "更新完成"
|
||||
log "更新完成 slot=${INSTANCE_SLOT} http://127.0.0.1:${API_PORT}/health"
|
||||
}
|
||||
|
||||
main_update "$@"
|
||||
|
||||
+51
-6
@@ -182,13 +182,15 @@ show_banner() {
|
||||
}
|
||||
|
||||
show_menu() {
|
||||
echo " 1) 一键部署策略机"
|
||||
echo " 1) 一键部署策略机(可选槽位 1/2/3)"
|
||||
echo " 2) 一键部署中控机"
|
||||
echo " 3) 一键卸载"
|
||||
echo " 4) 更新策略机"
|
||||
echo " 3) 一键卸载策略机(选槽位)"
|
||||
echo " 4) 更新策略机(选槽位 / 全部)"
|
||||
echo " 5) 更新中控机"
|
||||
echo " 0) 退出"
|
||||
echo ""
|
||||
echo " 槽位: 1→:5155 2→:5156 3→:5157(同机最多三套,实盘请只用 1)"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# 交互读入(兼容 curl|bash)
|
||||
@@ -224,6 +226,42 @@ deploy_control_node() {
|
||||
log "中控部署完成 → http://<本机IP>:5160 默认账号 admin / admin123"
|
||||
}
|
||||
|
||||
run_with_slot_env() {
|
||||
# 子脚本继承当前槽位变量
|
||||
env \
|
||||
INSTANCE_SLOT="${INSTANCE_SLOT}" \
|
||||
INSTALL_ROOT="${INSTALL_ROOT}" \
|
||||
API_PORT="${API_PORT}" \
|
||||
PM2_APP_NAME="${PM2_APP_NAME}" \
|
||||
SKIP_SLOT_PROMPT=1 \
|
||||
EHS_FROM_MANAGE=1 \
|
||||
"$@"
|
||||
}
|
||||
|
||||
prompt_update_target() {
|
||||
local line=""
|
||||
echo ""
|
||||
echo "更新目标:"
|
||||
echo " 1/2/3) 指定槽位"
|
||||
echo " a) 全部已安装槽位(串行,适合 2G 测机)"
|
||||
cm_read line "请选择 [1/2/3/a,默认1]: "
|
||||
line="${line:-1}"
|
||||
case "${line}" in
|
||||
a|A|all|ALL)
|
||||
EHS_UPDATE_MODE=all
|
||||
;;
|
||||
1|2|3)
|
||||
EHS_UPDATE_MODE=one
|
||||
resolve_slot "${line}"
|
||||
;;
|
||||
*)
|
||||
echo "无效选择,使用槽位 1"
|
||||
EHS_UPDATE_MODE=one
|
||||
resolve_slot 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
main_menu() {
|
||||
bootstrap_repo
|
||||
# shellcheck source=lib/common.sh
|
||||
@@ -237,16 +275,23 @@ main_menu() {
|
||||
cm_read choice "请选择 [0-5]: "
|
||||
case "${choice}" in
|
||||
1)
|
||||
bash "${LIB_DIR}/install.sh"
|
||||
prompt_instance_slot
|
||||
run_with_slot_env bash "${LIB_DIR}/install.sh"
|
||||
;;
|
||||
2)
|
||||
deploy_control_node
|
||||
;;
|
||||
3)
|
||||
bash "${LIB_DIR}/uninstall.sh"
|
||||
prompt_instance_slot
|
||||
run_with_slot_env bash "${LIB_DIR}/uninstall.sh"
|
||||
;;
|
||||
4)
|
||||
bash "${LIB_DIR}/update.sh"
|
||||
prompt_update_target
|
||||
if [[ "${EHS_UPDATE_MODE}" == "all" ]]; then
|
||||
env EHS_UPDATE_MODE=all SKIP_SLOT_PROMPT=1 bash "${LIB_DIR}/update.sh"
|
||||
else
|
||||
run_with_slot_env bash "${LIB_DIR}/update.sh"
|
||||
fi
|
||||
;;
|
||||
5)
|
||||
deploy_control_node
|
||||
|
||||
+32
-11
@@ -2,41 +2,57 @@
|
||||
# 一键更新/部署:仅 git pull,禁止 scp 传代码。
|
||||
# 用法:
|
||||
# bash /opt/eth_hedge_sim/deploy/pull_and_restart.sh
|
||||
# 或通过 manage.sh 选 1/3
|
||||
# bash /opt/eth_hedge_sim_2/deploy/pull_and_restart.sh
|
||||
# 或通过 manage.sh 选槽位后部署/更新
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
# 有 root 时:检测 Python / Node / PM2,缺则装、有则跳过(pull 前用当前脚本)
|
||||
if [[ -f "$ROOT/deploy/lib/common.sh" ]] && [[ "$(id -u)" -eq 0 ]]; then
|
||||
_COMMON="$ROOT/deploy/lib/common.sh"
|
||||
if [[ -f "$_COMMON" ]]; then
|
||||
# shellcheck source=lib/common.sh
|
||||
source "$ROOT/deploy/lib/common.sh"
|
||||
source "$_COMMON"
|
||||
apply_slot_for_root "$ROOT"
|
||||
fi
|
||||
|
||||
# 有 root 时:检测 Python / Node / PM2,缺则装、有则跳过(pull 前用当前脚本)
|
||||
if [[ -f "$_COMMON" ]] && [[ "$(id -u)" -eq 0 ]]; then
|
||||
ensure_system_deps
|
||||
fi
|
||||
|
||||
echo "[比特骆驼] pull @ $ROOT"
|
||||
echo "[比特骆驼] pull @ $ROOT (slot=${INSTANCE_SLOT:-?} port=${API_PORT:-?})"
|
||||
if [[ -d "$ROOT/.git" ]]; then
|
||||
git fetch --all --prune
|
||||
git pull --ff-only
|
||||
fi
|
||||
|
||||
# pull 后再检测一次,确保用上仓库里最新的 python3-venv / ensurepip 逻辑
|
||||
if [[ -f "$ROOT/deploy/lib/common.sh" ]] && [[ "$(id -u)" -eq 0 ]]; then
|
||||
if [[ -f "$_COMMON" ]]; then
|
||||
# shellcheck source=lib/common.sh
|
||||
source "$ROOT/deploy/lib/common.sh"
|
||||
source "$_COMMON"
|
||||
apply_slot_for_root "$ROOT"
|
||||
fi
|
||||
if [[ -f "$_COMMON" ]] && [[ "$(id -u)" -eq 0 ]]; then
|
||||
ensure_system_deps
|
||||
fi
|
||||
|
||||
if [[ ! -f "$ROOT/.env" ]]; then
|
||||
echo "[比特骆驼] missing .env — copy from example"
|
||||
cp "$ROOT/.env.example" "$ROOT/.env"
|
||||
# 云上测试机默认直连 OKX
|
||||
# 云上测试机默认直连 OKX;端口按槽位
|
||||
local_port="${API_PORT:-5155}"
|
||||
sed -i 's/^OKX_HTTP_PROXY=.*/OKX_HTTP_PROXY=/' "$ROOT/.env" || true
|
||||
sed -i 's/^API_PORT=.*/API_PORT=5155/' "$ROOT/.env" || true
|
||||
sed -i "s/^API_PORT=.*/API_PORT=${local_port}/" "$ROOT/.env" || true
|
||||
sed -i 's/^ENV_NAME=.*/ENV_NAME=test/' "$ROOT/.env" || true
|
||||
sed -i 's/^EXCHANGE=.*/EXCHANGE=okx/' "$ROOT/.env" || true
|
||||
echo "[比特骆驼] wrote .env — please review AUTH_* secrets"
|
||||
if [[ -f "$_COMMON" ]]; then
|
||||
secret="$(random_auth_secret)"
|
||||
if [[ -n "${secret}" ]]; then
|
||||
sed -i "s/^AUTH_SECRET=.*/AUTH_SECRET=${secret}/" "$ROOT/.env" || true
|
||||
fi
|
||||
fi
|
||||
echo "[比特骆驼] wrote .env — API_PORT=${local_port};请按需修改 AUTH_*"
|
||||
fi
|
||||
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
@@ -93,8 +109,13 @@ else
|
||||
echo "[比特骆驼] pm2 already present, skip install"
|
||||
fi
|
||||
|
||||
# 按本目录槽位重写 PM2 配置(避免 git pull 盖回槽位 1 硬编码)
|
||||
if [[ -f "$_COMMON" ]]; then
|
||||
write_ecosystem_config "$ROOT" "${PM2_APP_NAME}" "${API_PORT}"
|
||||
fi
|
||||
|
||||
# 仅 reload 本项目进程,禁止 pm2 restart all
|
||||
pm2 startOrReload "$ROOT/deploy/ecosystem.config.cjs" --update-env
|
||||
pm2 save
|
||||
|
||||
echo "[比特骆驼] done. health: http://127.0.0.1:5155/health"
|
||||
echo "[比特骆驼] done. slot=${INSTANCE_SLOT:-1} health: http://127.0.0.1:${API_PORT:-5155}/health"
|
||||
|
||||
Reference in New Issue
Block a user