From 33f61c9f1dc88ebf36f4143e36cf8aae671767e2 Mon Sep 17 00:00:00 2001 From: admin Date: Thu, 14 May 2026 14:55:53 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=B8=80=E9=94=AE=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E8=84=9A=E6=9C=AC=20start.sh=20(start/stop/restart/st?= =?UTF-8?q?atus/logs)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- start.sh | 249 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 249 insertions(+) create mode 100755 start.sh diff --git a/start.sh b/start.sh new file mode 100755 index 0000000..8214879 --- /dev/null +++ b/start.sh @@ -0,0 +1,249 @@ +#!/bin/bash +# KVM Manager 一键启动脚本 +# 用法: ./start.sh [start|stop|restart|status] +set -e + +# ── 配置 ────────────────────────────────────────────── +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +BACKEND_DIR="$SCRIPT_DIR/backend" +FRONTEND_DIR="$SCRIPT_DIR/frontend" +LOG_DIR="$SCRIPT_DIR/logs" +PID_DIR="$SCRIPT_DIR/.pid" + +BACKEND_PORT=8004 +FRONTEND_PORT=8006 +BACKEND_CMD="$BACKEND_DIR/venv/bin/python -m uvicorn app.main:app --host 0.0.0.0 --port $BACKEND_PORT" +FRONTEND_CMD="$BACKEND_DIR/venv/bin/python $FRONTEND_DIR/serve.py" + +# ── 颜色 ────────────────────────────────────────────── +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' + +# ── 工具函数 ────────────────────────────────────────── +info() { echo -e "${CYAN}[INFO]${NC} $1"; } +ok() { echo -e "${GREEN}[OK]${NC} $1"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $1"; } +fail() { echo -e "${RED}[FAIL]${NC} $1"; } + +mkdir -p "$LOG_DIR" "$PID_DIR" + +# 检查端口是否被占用,返回 PID +port_pid() { + lsof -ti:$1 2>/dev/null | head -1 +} + +# 等待端口可用 +wait_port() { + local port=$1 name=$2 max=10 count=0 + while [ $count -lt $max ]; do + if port_pid $port >/dev/null 2>&1; then + return 0 + fi + sleep 1 + count=$((count + 1)) + done + return 1 +} + +# ── 启动后端 ────────────────────────────────────────── +start_backend() { + info "启动后端服务 (端口 $BACKEND_PORT)..." + + # 检查是否已运行 + local existing_pid=$(port_pid $BACKEND_PORT) + if [ -n "$existing_pid" ]; then + warn "后端已在运行 (PID: $existing_pid)" + return 0 + fi + + # 检查 venv + if [ ! -d "$BACKEND_DIR/venv" ]; then + fail "未找到 Python 虚拟环境,请先运行: cd backend && python3 -m venv venv && source venv/bin/activate && pip install -r requirements.txt" + return 1 + fi + + # 检查 libvirtd + if ! systemctl is-active --quiet libvirtd 2>/dev/null; then + warn "libvirtd 未运行,尝试启动..." + systemctl start libvirtd 2>/dev/null || warn "libvirtd 启动失败,后端可能无法连接虚拟机" + fi + + cd "$BACKEND_DIR" + nohup $BACKEND_CMD > "$LOG_DIR/backend.log" 2>&1 & + local pid=$! + echo $pid > "$PID_DIR/backend.pid" + + sleep 2 + if port_pid $BACKEND_PORT >/dev/null 2>&1; then + ok "后端服务已启动 (PID: $pid, 端口: $BACKEND_PORT)" + ok "日志: $LOG_DIR/backend.log" + else + fail "后端服务启动失败,查看日志:" + tail -20 "$LOG_DIR/backend.log" + return 1 + fi +} + +# ── 启动前端 ────────────────────────────────────────── +start_frontend() { + info "启动前端服务 (端口 $FRONTEND_PORT)..." + + local existing_pid=$(port_pid $FRONTEND_PORT) + if [ -n "$existing_pid" ]; then + warn "前端已在运行 (PID: $existing_pid)" + return 0 + fi + + # 检查 dist + if [ ! -d "$FRONTEND_DIR/dist" ]; then + warn "未找到前端构建产物,正在构建..." + cd "$FRONTEND_DIR" + npm install --silent && npm run build + if [ ! -d "$FRONTEND_DIR/dist" ]; then + fail "前端构建失败" + return 1 + fi + ok "前端构建完成" + fi + + cd "$FRONTEND_DIR" + nohup $FRONTEND_CMD > "$LOG_DIR/frontend.log" 2>&1 & + local pid=$! + echo $pid > "$PID_DIR/frontend.pid" + + sleep 2 + if port_pid $FRONTEND_PORT >/dev/null 2>&1; then + ok "前端服务已启动 (PID: $pid, 端口: $FRONTEND_PORT)" + ok "日志: $LOG_DIR/frontend.log" + else + fail "前端服务启动失败,查看日志:" + tail -20 "$LOG_DIR/frontend.log" + return 1 + fi +} + +# ── 停止服务 ────────────────────────────────────────── +stop_service() { + local name=$1 port=$2 pidfile=$PID_DIR/$3.pid + info "停止 $name (端口 $port)..." + + # 先尝试 PID 文件 + if [ -f "$pidfile" ]; then + local pid=$(cat "$pidfile") + if ps -p "$pid" >/dev/null 2>&1; then + kill "$pid" 2>/dev/null && ok "$name 已停止 (PID: $pid)" || warn "$name 停止失败" + fi + rm -f "$pidfile" + fi + + # 再检查端口残留 + local residual=$(port_pid $port) + if [ -n "$residual" ]; then + kill "$residual" 2>/dev/null && ok "$name 残留进程已清理 (PID: $residual)" || true + fi +} + +stop_all() { + info "停止所有服务..." + stop_service "后端" $BACKEND_PORT "backend" + stop_service "前端" $FRONTEND_PORT "frontend" + ok "所有服务已停止" +} + +# ── 状态 ────────────────────────────────────────────── +show_status() { + echo "" + echo -e "${CYAN}========================================${NC}" + echo -e "${CYAN} KVM Manager 服务状态${NC}" + echo -e "${CYAN}========================================${NC}" + + # 后端 + local bpid=$(port_pid $BACKEND_PORT) + if [ -n "$bpid" ]; then + echo -e " 后端: ${GREEN}● 运行中${NC} PID: $bpid 端口: $BACKEND_PORT" + else + echo -e " 后端: ${RED}○ 未运行${NC}" + fi + + # 前端 + local fpid=$(port_pid $FRONTEND_PORT) + if [ -n "$fpid" ]; then + echo -e " 前端: ${GREEN}● 运行中${NC} PID: $fpid 端口: $FRONTEND_PORT" + else + echo -e " 前端: ${RED}○ 未运行${NC}" + fi + + echo "" + echo -e " 访问地址: ${YELLOW}http://localhost:$FRONTEND_PORT${NC}" + echo -e " API文档: ${YELLOW}http://localhost:$BACKEND_PORT/docs${NC}" + echo -e " 日志目录: ${YELLOW}$LOG_DIR${NC}" + echo "" +} + +# ── 查看日志 ────────────────────────────────────────── +show_logs() { + local target=${1:-all} + case $target in + backend|b) tail -f "$LOG_DIR/backend.log" 2>/dev/null || fail "后端日志不存在" ;; + frontend|f) tail -f "$LOG_DIR/frontend.log" 2>/dev/null || fail "前端日志不存在" ;; + *) tail -f "$LOG_DIR/backend.log" "$LOG_DIR/frontend.log" 2>/dev/null || fail "日志不存在" ;; + esac +} + +# ── 主入口 ──────────────────────────────────────────── +usage() { + echo "" + echo -e "${CYAN}KVM Manager 一键启动脚本${NC}" + echo "" + echo "用法: $0 <命令>" + echo "" + echo "命令:" + echo " start 启动所有服务 (默认)" + echo " stop 停止所有服务" + echo " restart 重启所有服务" + echo " status 查看服务状态" + echo " logs 查看日志 (logs backend/frontend)" + echo "" + echo "示例:" + echo " $0 # 启动所有" + echo " $0 start # 启动所有" + echo " $0 stop # 停止所有" + echo " $0 restart # 重启所有" + echo " $0 status # 查看状态" + echo " $0 logs backend # 查看后端日志" + echo "" +} + +case "${1:-start}" in + start) + start_backend + start_frontend + show_status + ;; + stop) + stop_all + ;; + restart) + stop_all + sleep 1 + start_backend + start_frontend + show_status + ;; + status) + show_status + ;; + logs) + show_logs "${2:-all}" + ;; + -h|--help|help) + usage + ;; + *) + usage + exit 1 + ;; +esac