diff --git a/servers/scripts/wm.sh b/servers/scripts/wm.sh new file mode 100755 index 0000000..a974793 --- /dev/null +++ b/servers/scripts/wm.sh @@ -0,0 +1,250 @@ +#!/usr/bin/env bash +# walletman 远程管理:deploy / start / stop / restart / status +# 用法: ./wm.sh deploy|start|stop|restart|status + +set -euo pipefail + +JUMP_HOST="${JUMP_HOST:-ipay-jump}" +TARGET_HOST="${TARGET_HOST:-ipay-test}" +REMOTE_BASE="${REMOTE_BASE:-/home/ec2-user/walletman}" +REMOTE_BIN_DIR="${REMOTE_BASE}/cmd/server" +REMOTE_BIN="${REMOTE_BIN_DIR}/ipay.bin" +REMOTE_WALLETS="${REMOTE_BASE}/cmd/wallets.json" +REMOTE_FCM_CONFIG="${REMOTE_BIN_DIR}/config/fcm-service-account.json" +REMOTE_LOG="${REMOTE_BASE}/walletman.log" +REMOTE_PID="${REMOTE_BASE}/walletman.pid" +GO_TLS_FLAG="${GO_TLS_FLAG:--tls android}" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +WALLETMAN_DIR="$(cd "${SCRIPT_DIR}/../walletman" && pwd)" + +log() { printf '\033[1;32m[wm]\033[0m %s\n' "$*"; } +warn() { printf '\033[1;33m[wm]\033[0m %s\n' "$*"; } +die() { printf '\033[1;31m[wm]\033[0m %s\n' "$*" >&2; exit 1; } + +ssh_jump() { + ssh -o ClearAllForwardings=yes -o BatchMode=yes "${JUMP_HOST}" "$@" +} + +ssh_target() { + ssh_jump ssh -o BatchMode=yes "${TARGET_HOST}" "$@" +} + +remote_script() { + ssh_target bash -s +} + +# 远端 start/stop/status(deploy 也会 source 这段逻辑) +run_remote_ctl() { + local action="$1" + local check_health="${2:-0}" + remote_script </dev/null || true) + if [[ -n "\${old_pid}" ]] && kill -0 "\${old_pid}" 2>/dev/null; then + echo "stop pid=\${old_pid}" + kill "\${old_pid}" || true + sleep 1 + kill -9 "\${old_pid}" 2>/dev/null || true + fi + rm -f "\${REMOTE_PID}" + fi + if pkill -f "\${REMOTE_BIN}" 2>/dev/null; then + echo "stop pkill \${REMOTE_BIN}" + sleep 1 + fi +} + +start_walletman() { + if [[ ! -x "\${REMOTE_BIN}" ]]; then + echo "binary not found: \${REMOTE_BIN}" >&2 + exit 1 + fi + cd "\${REMOTE_BIN_DIR}" + nohup "\${REMOTE_BIN}" \${GO_TLS_FLAG} >> "\${REMOTE_LOG}" 2>&1 & + echo \$! > "\${REMOTE_PID}" + echo "started pid=\$(cat "\${REMOTE_PID}")" +} + +status_walletman() { + if [[ -f "\${REMOTE_PID}" ]]; then + pid=\$(cat "\${REMOTE_PID}" 2>/dev/null || true) + if [[ -n "\${pid}" ]] && kill -0 "\${pid}" 2>/dev/null; then + echo "running pid=\${pid}" + else + echo "not running (stale pid file)" + fi + else + echo "not running" + fi + if curl -sf --max-time 5 http://127.0.0.1:16000/wallets >/dev/null; then + echo "health ok" + else + echo "health fail" + exit 1 + fi +} + +case "\${ACTION}" in + stop) stop_walletman ;; + start) + stop_walletman + start_walletman + sleep 2 + ;; + restart) + stop_walletman + start_walletman + sleep 2 + ;; + status) status_walletman; exit 0 ;; + *) echo "unknown action \${ACTION}" >&2; exit 1 ;; +esac + +if [[ "\${CHECK_HEALTH}" == "1" ]]; then + if curl -sf --max-time 5 http://127.0.0.1:16000/wallets >/dev/null; then + echo "health ok: http://127.0.0.1:16000/wallets" + else + echo "health check failed, tail log:" >&2 + tail -n 30 "\${REMOTE_LOG}" >&2 || true + exit 1 + fi +fi +EOF +} + +cmd_start() { + log "start ${TARGET_HOST}" + run_remote_ctl start 1 +} + +cmd_stop() { + log "stop ${TARGET_HOST}" + run_remote_ctl stop 0 + log "已停止" +} + +cmd_restart() { + log "restart ${TARGET_HOST}" + run_remote_ctl restart 1 +} + +cmd_status() { + log "status ${TARGET_HOST}" + run_remote_ctl status +} + +cmd_deploy() { + local build_dir staging tarball + build_dir="$(mktemp -d)" + staging="${build_dir}/staging" + tarball="${build_dir}/walletman-deploy.tgz" + trap 'rm -rf "${build_dir}"' EXIT + + local wallets_json="${WALLETMAN_DIR}/cmd/wallets.json" + local fcm_config="${WALLETMAN_DIR}/cmd/server/config/fcm-service-account.json" + [[ -f "${wallets_json}" ]] || die "缺少 ${wallets_json}" + [[ -f "${fcm_config}" ]] || die "缺少 ${fcm_config}" + + log "构建 linux/amd64 二进制..." + mkdir -p "${staging}/bin" "${staging}/test" "${staging}/cmd" "${staging}/config" + ( + cd "${WALLETMAN_DIR}" + GOOS=linux GOARCH=amd64 go build -buildvcs=false -ldflags="-s -w" -o "${staging}/bin/ipay.bin" ./cmd/server + ) + cp -R "${WALLETMAN_DIR}/test/." "${staging}/test/" + cp "${wallets_json}" "${staging}/cmd/wallets.json" + cp "${fcm_config}" "${staging}/config/fcm-service-account.json" + if [[ "$(uname -s)" == Darwin ]]; then + xattr -cr "${staging}" 2>/dev/null || true + fi + + log "打包..." + if [[ "$(uname -s)" == Darwin ]]; then + COPYFILE_DISABLE=1 tar --no-xattrs -czf "${tarball}" -C "${staging}" bin test cmd config 2>/dev/null \ + || COPYFILE_DISABLE=1 tar -czf "${tarball}" -C "${staging}" bin test cmd config + else + tar czf "${tarball}" -C "${staging}" bin test cmd config + fi + + log "上传到 ${JUMP_HOST}..." + scp -o ClearAllForwardings=yes "${tarball}" "${JUMP_HOST}:/tmp/walletman-deploy.tgz" + ssh_jump scp "/tmp/walletman-deploy.tgz" "${TARGET_HOST}:/tmp/walletman-deploy.tgz" + + log "分发到 ${TARGET_HOST}:${REMOTE_BASE} ..." + remote_script </dev/null \ + || tar xzf walletman-deploy.tgz 2>/dev/null \ + || tar xzf walletman-deploy.tgz +rm -f walletman-deploy.tgz + +if [[ -f "\${REMOTE_BIN}" ]]; then + cp "\${REMOTE_BIN}" "\${REMOTE_BIN}.bak.\$(date +%Y%m%d%H%M%S)" +fi +install -m 755 bin/ipay.bin "\${REMOTE_BIN}" +rsync -a test/ "\${REMOTE_BASE}/test/" +ln -sfn ../../test "\${REMOTE_BIN_DIR}/test" + +if [[ -f "\${REMOTE_WALLETS}" ]]; then + cp "\${REMOTE_WALLETS}" "\${REMOTE_WALLETS}.bak.\$(date +%Y%m%d%H%M%S)" +fi +install -m 644 cmd/wallets.json "\${REMOTE_WALLETS}" +install -m 600 config/fcm-service-account.json "\${REMOTE_FCM_CONFIG}" +rm -f "\${REMOTE_BIN_DIR}/wallets.json" +EOF + + ssh_jump rm -f /tmp/walletman-deploy.tgz + log "文件已更新,重启服务..." + run_remote_ctl restart 1 + log "部署完成: ${TARGET_HOST}:${REMOTE_BIN}" + log "wallets.json → ${REMOTE_WALLETS}" + log "fcm config → ${REMOTE_FCM_CONFIG}" +} + +usage() { + cat < + + deploy 构建并部署到 ${TARGET_HOST},然后 restart + start 启动远端 walletman + stop 停止远端 walletman + restart 重启远端 walletman + status 查看进程与健康检查 + +环境变量: JUMP_HOST TARGET_HOST REMOTE_BASE GO_TLS_FLAG +EOF +} + +main() { + local cmd="${1:-}" + case "${cmd}" in + deploy|--deploy) cmd_deploy ;; + start|--start) cmd_start ;; + stop|--stop) cmd_stop ;; + restart|--restart) cmd_restart ;; + status|--status) cmd_status ;; + -h|--help|help|"") usage ;; + *) die "未知命令: ${cmd}(见 --help)" ;; + esac +} + +main "$@"