#!/bin/bash #======================================================================= # FILE: scripts/deploy.sh # DESC: 部署 mission + 7 个 systemd 服务(moosdb / pPowerManger / # pPowerMangerHost / pCCU / pCanBridge / pMotor / pELoad)到目标 # 板卡 (RK3588 / Ubuntu 22.04)。只安装服务 + daemon-reload, # 默认不启动、不自启。 # # 注意:二进制由 ./scripts/build-board.sh 在板卡原生编译并部署到 # /root/work/h100/bin/(交叉编译已移除),本脚本不再推送二进制。 # # 用法: # ./scripts/deploy.sh setup-ssh 一次性:生成 ed25519 key + ssh-copy-id # ./scripts/deploy.sh 默认:推送 mission + 装 7 个 # systemd 服务 + daemon-reload(不启动) # ./scripts/deploy.sh --start 部署后按依赖顺序启动服务 # ./scripts/deploy.sh status 板卡各服务状态 # ./scripts/deploy.sh stop 停止各服务 # ./scripts/deploy.sh help 显示帮助 # # 参数: # --host 目标主机(默认 192.168.0.223) # --user 登录用户(默认 root) # --board-dir 板卡部署根目录(默认 /root/work/h100) # --start 部署后立即启动服务 # --ccu-host 覆盖 mission 中 pPowerManger 的 CCU 地址 (ccuhost) # --ccu-port 覆盖 mission 中 pPowerManger 的 CCU 端口 (ccuport) # # 板卡布局: # /root/work/h100/bin/ 二进制(由 build-board.sh 板卡编译产出) # /root/work/h100/missions/ 板卡 mission h100.moos # /root/work/h100/data/ 数据库存储目录 (power_data.db 等) # /etc/systemd/system/ moosdb.service / pPowerManger.service / # pPowerMangerHost.service / pCCU.service / # pCanBridge.service / pMotor.service / # pELoad.service #======================================================================= set -uo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "${SCRIPT_DIR}")" HOST="192.168.0.223" USER="root" BOARD_DIR="/root/work/h100" DO_START=0 CCU_HOST="" CCU_PORT="" SERVICES=(moosdb pPowerManger pPowerMangerHost pCCU pCanBridge pMotor pELoad) info() { printf '\033[1;36m[deploy]\033[0m %s\n' "$*"; } ok() { printf '\033[1;32m[deploy]\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m[deploy]\033[0m %s\n' "$*"; } err() { printf '\033[1;31m[deploy]\033[0m %s\n' "$*"; } usage() { sed -n '2,35p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//' exit 0 } #------------------------------------------------------------------- # 参数解析 #------------------------------------------------------------------- ACTION="" while [ $# -gt 0 ]; do case "$1" in --host) [ $# -ge 2 ] || { err "--host 需要参数"; exit 1; }; HOST="$2"; shift 2 ;; --user) [ $# -ge 2 ] || { err "--user 需要参数"; exit 1; }; USER="$2"; shift 2 ;; --board-dir)[ $# -ge 2 ] || { err "--board-dir 需要参数"; exit 1; }; BOARD_DIR="$2"; shift 2 ;; --start) DO_START=1; shift ;; --ccu-host) [ $# -ge 2 ] || { err "--ccu-host 需要参数"; exit 1; }; CCU_HOST="$2"; shift 2 ;; --ccu-port) [ $# -ge 2 ] || { err "--ccu-port 需要参数"; exit 1; }; CCU_PORT="$2"; shift 2 ;; setup-ssh|status|stop|help|-h|--help) ACTION="$1"; shift ;; "") shift ;; *) err "未知参数: $1(见 help)"; exit 1 ;; esac done [ -n "${ACTION}" ] || ACTION="deploy" case "${CCU_PORT}" in ""|*[!0-9]*) [ -z "${CCU_PORT}" ] || { err "--ccu-port 必须是数字端口: ${CCU_PORT}"; exit 1; } ;; esac SSH_TARGET="${USER}@${HOST}" SSH="ssh -o BatchMode=yes -o ConnectTimeout=5" SCP="scp -o BatchMode=yes -o ConnectTimeout=5" #------------------------------------------------------------------- # 命令: setup-ssh #------------------------------------------------------------------- cmd_setup_ssh() { local key="$HOME/.ssh/id_ed25519" if [ ! -f "${key}" ]; then info "未发现 SSH key,生成 ed25519 key ..." mkdir -p "$HOME/.ssh" && chmod 700 "$HOME/.ssh" ssh-keygen -t ed25519 -N '' -f "${key}" fi info "上传公钥到 ${SSH_TARGET}(会提示输入密码,仅此一次)..." ssh-copy-id -o ConnectTimeout=5 "${SSH_TARGET}" ok "免密 SSH 已配置。验证: ssh ${SSH_TARGET}" } #------------------------------------------------------------------- # 前置检查 #------------------------------------------------------------------- check_ssh() { if ! ${SSH} "${SSH_TARGET}" 'true' 2>/dev/null; then err "无法免密 SSH 到 ${SSH_TARGET}" err "请先执行: ./scripts/deploy.sh setup-ssh" return 1 fi ok "SSH 连接正常: ${SSH_TARGET}" } #------------------------------------------------------------------- # 生成 systemd unit(含板卡绝对路径) #------------------------------------------------------------------- gen_moosdb_unit() { # MOOSDB 路径在板卡探测;探测失败给出提示 local moosdb_bin moosdb_bin="$(${SSH} "${SSH_TARGET}" 'command -v MOOSDB || true' 2>/dev/null)" if [ -z "${moosdb_bin}" ]; then moosdb_bin="$(command -v MOOSDB || true)" warn "板卡未在 PATH 找到 MOOSDB,回退本机路径 ${moosdb_bin:-"(未找到)"}" [ -n "${moosdb_bin}" ] || { err "MOOSDB 路径未知,无法生成 moosdb.service"; return 1; } fi ok "MOOSDB 路径: ${moosdb_bin}" >&2 cat < "${f}.tmp" && mv "${f}.tmp" "${f}" fi } #------------------------------------------------------------------- # 命令: deploy #------------------------------------------------------------------- cmd_deploy() { check_ssh || return 1 [ -f "${PROJECT_ROOT}/missions/h100.moos" ] || { err "缺少板卡 mission: missions/h100.moos"; return 1; } # 1. 创建板卡目录 + 推送 mission info "创建板卡目录 ${BOARD_DIR}/{bin,missions,data} ..." ${SSH} "${SSH_TARGET}" "mkdir -p ${BOARD_DIR}/bin ${BOARD_DIR}/missions ${BOARD_DIR}/data" || { err "创建目录失败"; return 1; } info "推送 mission h100.moos ..." local mission_src="${PROJECT_ROOT}/missions/h100.moos" local mission_push="${mission_src}" tmp_moos="" if [ -n "${CCU_HOST}" ] || [ -n "${CCU_PORT}" ]; then tmp_moos="$(mktemp)" cp "${mission_src}" "${tmp_moos}" [ -n "${CCU_HOST}" ] && upsert_moos_param "${tmp_moos}" ccuhost "${CCU_HOST}" [ -n "${CCU_PORT}" ] && upsert_moos_param "${tmp_moos}" ccuport "${CCU_PORT}" mission_push="${tmp_moos}" info "CCU 地址覆盖: ccuhost=${CCU_HOST:-<保持原值>} ccuport=${CCU_PORT:-<保持原值>}" fi ${SCP} -q "${mission_push}" \ "${SSH_TARGET}:${BOARD_DIR}/missions/" || { err "推送 mission 失败"; [ -n "${tmp_moos}" ] && rm -f "${tmp_moos}"; return 1; } [ -n "${tmp_moos}" ] && rm -f "${tmp_moos}" ok "mission 已推送(二进制由 build-board.sh 在板卡编译部署)" # 2. 生成并安装 4 个 systemd unit local unit for s in "${SERVICES[@]}"; do info "生成 ${s}.service ..." if [ "${s}" = "moosdb" ]; then unit="$(gen_moosdb_unit)" || return 1 else unit="$(gen_app_unit "${s}")" fi printf '%s\n' "${unit}" | ${SSH} "${SSH_TARGET}" "cat > /etc/systemd/system/${s}.service" ok "${s}.service 已安装" done # 3. daemon-reload(不 enable,不自启) info "systemctl daemon-reload ..." ${SSH} "${SSH_TARGET}" "systemctl daemon-reload && systemctl reset-failed ${SERVICES[*]} 2>/dev/null || true" ok "服务已安装但未启用自启(systemctl is-enabled 应输出 disabled)" # 4. 可选启动 if [ "${DO_START}" = "1" ]; then cmd_start else echo "" info "部署完成。手动启动(或加 --start):" echo " systemctl start moosdb pPowerManger pPowerMangerHost pCCU pCanBridge pMotor pELoad" echo " 浏览器: http://${HOST}:18080 (上位机模拟)" echo " http://${HOST}:8090 (pPowerManger)" echo " http://${HOST}:8080 (pCCU)" echo " http://${HOST}:18082 (pELoad)" fi } #------------------------------------------------------------------- # 命令: start / status / stop #------------------------------------------------------------------- cmd_start() { info "启动服务 (moosdb -> pPowerManger / pPowerMangerHost / pCCU / pCanBridge / pMotor / pELoad) ..." ${SSH} "${SSH_TARGET}" "systemctl start moosdb && sleep 1 && \ systemctl start pPowerManger pPowerMangerHost pCCU pCanBridge pMotor pELoad" || { err "启动失败"; return 1; } ok "服务已启动" cmd_status } cmd_status() { ${SSH} "${SSH_TARGET}" "systemctl --no-pager status ${SERVICES[*]}" || true } cmd_stop() { ${SSH} "${SSH_TARGET}" "systemctl stop pELoad pMotor pCanBridge pPowerMangerHost pPowerManger pCCU moosdb" && \ ok "服务已停止" || err "停止服务失败" } #------------------------------------------------------------------- # 命令入口 #------------------------------------------------------------------- case "${ACTION}" in deploy) cmd_deploy ;; setup-ssh) cmd_setup_ssh ;; status) cmd_status ;; stop) cmd_stop ;; help|-h|--help) usage ;; *) usage ;; esac