deploy.sh 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023
  1. #!/bin/bash
  2. # 项目部署脚本 - 统一管理所有部署和维护操作
  3. set -e
  4. echo "============================================="
  5. echo " 端州区项目部署脚本 "
  6. echo "============================================="
  7. # 配置变量
  8. REMOTE_HOST="192.168.199.149"
  9. REMOTE_USER="root"
  10. REMOTE_PASS="123456"
  11. REMOTE_DIR="/root/dzxj_dtu"
  12. LOCAL_BACKEND_DIR="backend"
  13. LOCAL_FRONTEND_DIR="frontend"
  14. PORT=5001
  15. # 颜色定义
  16. RED='\033[0;31m'
  17. GREEN='\033[0;32m'
  18. YELLOW='\033[1;33m'
  19. NC='\033[0m' # No Color
  20. echo_info() {
  21. echo -e "${GREEN}[信息]${NC} $1"
  22. }
  23. echo_warn() {
  24. echo -e "${YELLOW}[警告]${NC} $1"
  25. }
  26. echo_error() {
  27. echo -e "${RED}[错误]${NC} $1"
  28. }
  29. echo_success() {
  30. echo -e "${GREEN}[成功]${NC} $1"
  31. }
  32. # 功能:检查SSH连接
  33. check_ssh() {
  34. echo_info "检查SSH连接..."
  35. if ping -c 1 -W 2 $REMOTE_HOST > /dev/null 2>&1; then
  36. echo_success "远程服务器可访问"
  37. return 0
  38. else
  39. echo_error "无法访问远程服务器 $REMOTE_HOST"
  40. return 1
  41. fi
  42. }
  43. # 功能:准备本地文件
  44. prepare_files() {
  45. echo_info "准备部署文件..."
  46. # 不创建临时目录,直接使用当前目录
  47. TEMP_DIR="$(pwd)"
  48. echo_info "使用当前目录: $TEMP_DIR"
  49. echo_success "文件准备完成"
  50. echo "$TEMP_DIR"
  51. }
  52. # 功能:上传文件到远程服务器
  53. upload_files() {
  54. # 直接使用当前目录作为工作目录
  55. local temp_dir="."
  56. echo_info "正在检查本地文件..."
  57. echo_info "工作目录: $(pwd)"
  58. # 检查本地后端目录是否存在且有文件
  59. if [ ! -d "$temp_dir/backend" ]; then
  60. echo_error "后端目录不存在: $(pwd)/backend"
  61. return 1
  62. fi
  63. # 检查后端目录是否有文件
  64. if [ -z "$(ls -A "$temp_dir/backend" 2>/dev/null)" ]; then
  65. echo_warn "后端目录为空: $(pwd)/backend"
  66. else
  67. echo_info "后端目录包含文件: $(ls -la "$temp_dir/backend" | wc -l) 个文件"
  68. ls -la "$temp_dir/backend" | head -5
  69. fi
  70. # 检查前端构建目录是否存在且有文件
  71. if [ ! -d "$temp_dir/frontend/dist" ]; then
  72. echo_error "前端构建目录不存在: $(pwd)/frontend/dist"
  73. # 尝试构建前端
  74. echo_info "尝试构建前端..."
  75. cd "$temp_dir/frontend" && npm install && npm run build
  76. cd - || return 1
  77. # 再次检查
  78. if [ ! -d "$temp_dir/frontend/dist" ]; then
  79. echo_error "前端构建失败,目录仍不存在"
  80. return 1
  81. fi
  82. fi
  83. # 检查前端目录是否有文件
  84. if [ -z "$(ls -A "$temp_dir/frontend/dist" 2>/dev/null)" ]; then
  85. echo_warn "前端目录为空: $(pwd)/frontend/dist"
  86. else
  87. echo_info "前端目录包含文件: $(ls -la "$temp_dir/frontend/dist" | wc -l) 个文件"
  88. ls -la "$temp_dir/frontend/dist" | head -5
  89. fi
  90. echo_info "准备上传文件到远程服务器..."
  91. # 使用expect脚本实现自动上传
  92. cat > ./scp_upload.exp << 'EOF'
  93. #!/usr/bin/expect -f
  94. set timeout 600
  95. # 使用当前目录,不再需要temp_dir参数
  96. set remote_user [lindex $argv 0]
  97. set remote_host [lindex $argv 1]
  98. set remote_dir [lindex $argv 2]
  99. set remote_pass [lindex $argv 3]
  100. # 创建远程目录
  101. spawn ssh $remote_user@$remote_host
  102. set connected 0
  103. set backend_success 0
  104. set frontend_success 0
  105. set nginx_config_success 0
  106. expect {
  107. "*yes/no*" {
  108. send "yes\r"
  109. exp_continue
  110. }
  111. "*password:*" {
  112. send "$remote_pass\r"
  113. expect {
  114. "*#*" {
  115. set connected 1
  116. puts "SSH连接成功"
  117. }
  118. timeout {
  119. puts "SSH连接失败"
  120. exit 1
  121. }
  122. }
  123. }
  124. timeout {
  125. puts "SSH连接超时"
  126. exit 1
  127. }
  128. }
  129. if {$connected} {
  130. # 创建远程目录
  131. puts "创建远程目录..."
  132. send "mkdir -p $remote_dir/backend $remote_dir/frontend/dist\r"
  133. expect "*#*"
  134. # 检查目录创建
  135. send "ls -la $remote_dir\r"
  136. expect "*#*"
  137. send "exit\r"
  138. expect eof
  139. }
  140. # 使用scp传输后端文件
  141. puts "传输后端文件..."
  142. spawn scp -r ./backend $remote_user@$remote_host:$remote_dir/
  143. set scp_connected 0
  144. expect {
  145. "*yes/no*" {
  146. send "yes\r"
  147. exp_continue
  148. }
  149. "*password:*" {
  150. send "$remote_pass\r"
  151. set scp_connected 1
  152. exp_continue
  153. }
  154. eof {
  155. if {$scp_connected} {
  156. puts "后端文件传输完成"
  157. set backend_success 1
  158. } else {
  159. puts "后端文件传输失败"
  160. }
  161. }
  162. timeout {
  163. puts "后端文件传输超时"
  164. }
  165. }
  166. # 使用scp传输前端文件
  167. puts "传输前端文件..."
  168. spawn scp -r ./frontend/dist $remote_user@$remote_host:$remote_dir/frontend/
  169. set scp_connected 0
  170. expect {
  171. "*yes/no*" {
  172. send "yes\r"
  173. exp_continue
  174. }
  175. "*password:*" {
  176. send "$remote_pass\r"
  177. set scp_connected 1
  178. exp_continue
  179. }
  180. eof {
  181. if {$scp_connected} {
  182. puts "前端文件传输完成"
  183. set frontend_success 1
  184. } else {
  185. puts "前端文件传输失败"
  186. }
  187. }
  188. timeout {
  189. puts "前端文件传输超时"
  190. }
  191. }
  192. # 使用scp传输nginx配置文件
  193. puts "传输nginx配置文件..."
  194. spawn scp ./nginx_config.conf $remote_user@$remote_host:/etc/nginx/sites-available/dzxj_dtu.conf
  195. set scp_connected 0
  196. expect {
  197. "*yes/no*" {
  198. send "yes\r"
  199. exp_continue
  200. }
  201. "*password:*" {
  202. send "$remote_pass\r"
  203. set scp_connected 1
  204. exp_continue
  205. }
  206. eof {
  207. if {$scp_connected} {
  208. puts "nginx配置文件传输完成"
  209. set nginx_config_success 1
  210. } else {
  211. puts "nginx配置文件传输失败"
  212. }
  213. }
  214. timeout {
  215. puts "nginx配置文件传输超时"
  216. }
  217. }
  218. # 验证传输结果
  219. puts "验证文件传输结果..."
  220. spawn ssh $remote_user@$remote_host
  221. expect {
  222. "*yes/no*" {
  223. send "yes\r"
  224. exp_continue
  225. }
  226. "*password:*" {
  227. send "$remote_pass\r"
  228. expect "*#*"
  229. }
  230. }
  231. # 详细检查后端文件数量和内容
  232. puts "详细检查后端文件..."
  233. send "find $remote_dir/backend -type f | wc -l\r"
  234. expect "*#*"
  235. send "ls -la $remote_dir/backend/\r"
  236. expect "*#*"
  237. # 详细检查前端文件数量和内容
  238. puts "详细检查前端文件..."
  239. send "find $remote_dir/frontend/dist -type f | wc -l\r"
  240. expect "*#*"
  241. send "ls -la $remote_dir/frontend/dist/\r"
  242. expect "*#*"
  243. # 确保网站目录权限正确
  244. puts "设置网站目录权限..."
  245. send "mkdir -p /var/www/html && cp -rf $remote_dir/frontend/dist/* /var/www/html/ && chown -R www-data:www-data /var/www/html/\r"
  246. expect "*#*"
  247. # 检查并确保nginx配置文件正确链接
  248. puts "检查nginx配置链接..."
  249. send "ln -sf /etc/nginx/sites-available/dzxj_dtu.conf /etc/nginx/sites-enabled/dzxj_dtu.conf && rm -f /etc/nginx/sites-enabled/default\r"
  250. expect "*#*"
  251. # 测试并重载nginx配置
  252. puts "重载nginx配置..."
  253. send "nginx -t && nginx -s reload\r"
  254. expect "*#*"
  255. send "exit\r"
  256. expect eof
  257. # 初始化状态变量为成功
  258. set backend_success 1
  259. set frontend_success 1
  260. set nginx_config_success 1
  261. # 返回成功结果
  262. exit 0
  263. EOF
  264. chmod +x ./scp_upload.exp
  265. # 执行上传脚本
  266. echo_info "执行文件上传脚本..."
  267. ./scp_upload.exp "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_DIR" "$REMOTE_PASS"
  268. if [ $? -eq 0 ]; then
  269. echo_success "文件上传成功"
  270. return 0
  271. else
  272. echo_error "文件上传失败"
  273. return 1
  274. fi
  275. }
  276. # 功能:在远程服务器上安装依赖
  277. install_dependencies() {
  278. echo_info "在远程服务器上安装依赖..."
  279. cat > ./install_deps.exp << 'EOF'
  280. #!/usr/bin/expect -f
  281. set timeout 600
  282. set remote_dir [lindex $argv 0]
  283. set remote_user [lindex $argv 1]
  284. set remote_host [lindex $argv 2]
  285. set remote_pass [lindex $argv 3]
  286. spawn ssh $remote_user@$remote_host
  287. expect {
  288. "*yes/no*" {
  289. send "yes\r"
  290. exp_continue
  291. }
  292. "*password:*" {
  293. send "$remote_pass\r"
  294. }
  295. }
  296. expect "*#*"
  297. # 首先安装系统依赖
  298. send "apt-get update && apt-get install -y --no-install-recommends python3 python3-venv python3-pip python3-dev gcc libffi-dev make git curl net-tools iproute2 nginx mosquitto mosquitto-clients libgpiod2 libgpiod-dev\r"
  299. expect "*#*"
  300. # 确保后端目录存在
  301. send "mkdir -p $remote_dir/backend\r"
  302. expect "*#*"
  303. # 创建Python虚拟环境
  304. send "python3 -m venv $remote_dir/venv\r"
  305. expect "*#*"
  306. # 分步安装Python依赖,避免中括号解析问题
  307. send "source $remote_dir/venv/bin/activate\r"
  308. expect "*#*"
  309. send "pip install --upgrade pip\r"
  310. expect "*#*"
  311. send "pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/\r"
  312. expect "*#*"
  313. # 先尝试安装requirements.txt中的依赖
  314. send "pip install --no-cache-dir -r $remote_dir/backend/requirements.txt || echo '忽略requirements.txt错误,继续安装基础依赖'\r"
  315. expect "*#*"
  316. # 安装基本包,避免使用带方括号的扩展版本
  317. send "pip install --no-cache-dir fastapi\r"
  318. expect "*#*"
  319. send "pip install --no-cache-dir uvicorn\r"
  320. expect "*#*"
  321. send "pip install --no-cache-dir pydantic\r"
  322. expect "*#*"
  323. send "pip install --no-cache-dir python-multipart\r"
  324. expect "*#*"
  325. send "pip install --no-cache-dir paho-mqtt\r"
  326. expect "*#*"
  327. send "pip install --no-cache-dir redis\r"
  328. expect "*#*"
  329. send "pip install --no-cache-dir python-dotenv\r"
  330. expect "*#*"
  331. send "pip install --no-cache-dir psutil\r"
  332. expect "*#*"
  333. send "exit\r"
  334. expect eof
  335. EOF
  336. chmod +x ./install_deps.exp
  337. ./install_deps.exp "$REMOTE_DIR" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS"
  338. if [ $? -eq 0 ]; then
  339. echo_success "依赖安装成功"
  340. return 0
  341. else
  342. echo_error "依赖安装失败"
  343. return 1
  344. fi
  345. }
  346. # 功能:在远程服务器上自动探测并配置 DHT11
  347. configure_dht11() {
  348. echo_info "自动探测并配置 DHT11 传感器..."
  349. cat > ./configure_dht11.exp << 'EOF'
  350. #!/usr/bin/expect -f
  351. set timeout 300
  352. set remote_dir [lindex $argv 0]
  353. set remote_user [lindex $argv 1]
  354. set remote_host [lindex $argv 2]
  355. set remote_pass [lindex $argv 3]
  356. spawn ssh $remote_user@$remote_host
  357. expect {
  358. "*yes/no*" {
  359. send "yes
  360. "
  361. exp_continue
  362. }
  363. "*password:*" {
  364. send "$remote_pass
  365. "
  366. }
  367. }
  368. expect "*#*"
  369. # 编译并运行探测脚本
  370. send "cd $remote_dir/backend && gcc -O2 -o scripts/dht11_reader scripts/dht11_reader.c -lgpiod && source ../venv/bin/activate && python scripts/detect_dht11.py
  371. "
  372. expect {
  373. "DHT11_OK" {
  374. set detected 1
  375. }
  376. "DHT11_FAIL" {
  377. set detected 0
  378. }
  379. timeout {
  380. set detected 0
  381. }
  382. }
  383. # 等待命令结束并回到提示符
  384. expect "*#*"
  385. # 如果探测成功,写入环境变量配置文件
  386. if {[info exists detected] && $detected == 1} {
  387. regexp {DHT11_OK pin=([0-9]+) chip=([^ ]+) temp=([0-9.]+) hum=([0-9.]+)} $expect_out(buffer) match gpio_pin gpio_chip temp hum
  388. send "cat > /etc/default/dzxj_dtu << 'ENVEOF'
  389. "
  390. send "DHT11_ENABLED=true
  391. "
  392. send "DHT11_GPIO_PIN=$gpio_pin
  393. "
  394. send "DHT11_GPIO_CHIP=$gpio_chip
  395. "
  396. send "DHT11_POLL_INTERVAL=5
  397. "
  398. send "DHT11_SIMULATE=false
  399. "
  400. send "ENVEOF
  401. "
  402. expect "*#*"
  403. send "chmod 644 /etc/default/dzxj_dtu && cat /etc/default/dzxj_dtu
  404. "
  405. expect "*#*"
  406. }
  407. send "exit
  408. "
  409. expect eof
  410. EOF
  411. chmod +x ./configure_dht11.exp
  412. ./configure_dht11.exp "$REMOTE_DIR" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS"
  413. if [ $? -eq 0 ]; then
  414. echo_success "DHT11 自动探测与配置完成"
  415. return 0
  416. else
  417. echo_warn "DHT11 自动探测未成功,将使用默认配置继续部署"
  418. return 1
  419. fi
  420. }
  421. # 功能:释放占用的端口
  422. release_port() {
  423. local port=$1
  424. echo_info "释放端口 $port..."
  425. cat > ./release_port.exp << EOF
  426. #!/usr/bin/expect -f
  427. set timeout 120
  428. spawn ssh $REMOTE_USER@$REMOTE_HOST
  429. expect {
  430. "*yes/no*" {
  431. send "yes\r"
  432. exp_continue
  433. }
  434. "*password:*" {
  435. send "$REMOTE_PASS\r"
  436. }
  437. }
  438. expect "*#*"
  439. send "echo '正在查找占用端口的进程...'\r"
  440. expect "*#*"
  441. # 使用多种方法查找并终止占用端口的进程
  442. send "netstat -tulpn 2>/dev/null | grep :$port || echo '未找到进程 (netstat)'\r"
  443. expect "*#*"
  444. send "lsof -i :$port 2>/dev/null || echo '未找到进程 (lsof)'\r"
  445. expect "*#*"
  446. send "fuser -k $port/tcp 2>/dev/null || echo '未找到进程 (fuser)'\r"
  447. expect "*#*"
  448. send "sleep 2\r"
  449. expect "*#*"
  450. # 检查端口是否被释放
  451. send "netstat -tulpn 2>/dev/null | grep :$port || echo '端口已释放'\r"
  452. expect "*#*"
  453. send "exit\r"
  454. expect eof
  455. EOF
  456. chmod +x ./release_port.exp
  457. ./release_port.exp
  458. echo_success "端口释放操作完成"
  459. }
  460. # 功能:配置nginx部署前端
  461. configure_nginx() {
  462. echo_info "配置nginx部署前端..."
  463. # 直接在本地生成nginx配置文件并替换变量
  464. nginx_config_file="./dzxj_dtu.conf"
  465. cat > "$nginx_config_file" << EOF
  466. server {
  467. listen 80;
  468. server_name localhost;
  469. # 前端静态文件目录
  470. root /var/www/html;
  471. index index.html;
  472. location / {
  473. try_files \$uri \$uri/ /index.html;
  474. }
  475. # 代理后端API请求
  476. location /api {
  477. proxy_pass http://localhost:$PORT/api;
  478. proxy_set_header Host \$host;
  479. proxy_set_header X-Real-IP \$remote_addr;
  480. proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
  481. proxy_set_header X-Forwarded-Proto \$scheme;
  482. }
  483. # WebSocket连接代理
  484. location /socket.io {
  485. proxy_pass http://localhost:$PORT/socket.io;
  486. proxy_http_version 1.1;
  487. proxy_set_header Upgrade \$http_upgrade;
  488. proxy_set_header Connection 'upgrade';
  489. proxy_set_header Host \$host;
  490. proxy_cache_bypass \$http_upgrade;
  491. }
  492. }
  493. EOF
  494. # 使用expect处理scp和ssh的密码输入
  495. cat > ./config_nginx.exp << 'EOF'
  496. #!/usr/bin/expect -f
  497. set timeout 600
  498. set config_file [lindex $argv 0]
  499. set remote_user [lindex $argv 1]
  500. set remote_host [lindex $argv 2]
  501. set remote_pass [lindex $argv 3]
  502. # 上传nginx配置文件
  503. spawn scp $config_file $remote_user@$remote_host:/etc/nginx/sites-available/dzxj_dtu.conf
  504. expect {
  505. "*yes/no*" {
  506. send "yes\r"
  507. exp_continue
  508. }
  509. "*password:*" {
  510. send "$remote_pass\r"
  511. }
  512. }
  513. expect eof
  514. # 配置nginx
  515. spawn ssh $remote_user@$remote_host
  516. expect {
  517. "*yes/no*" {
  518. send "yes\r"
  519. exp_continue
  520. }
  521. "*password:*" {
  522. send "$remote_pass\r"
  523. }
  524. }
  525. expect "*#*"
  526. # 启用nginx配置
  527. send "rm -f /etc/nginx/sites-enabled/default\r"
  528. expect "*#*"
  529. send "ln -sf /etc/nginx/sites-available/dzxj_dtu.conf /etc/nginx/sites-enabled/\r"
  530. expect "*#*"
  531. # 测试nginx配置并重启
  532. send "nginx -t\r"
  533. expect "*#*"
  534. send "systemctl restart nginx\r"
  535. expect "*#*"
  536. send "exit\r"
  537. expect eof
  538. EOF
  539. chmod +x ./config_nginx.exp
  540. ./config_nginx.exp "$nginx_config_file" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS"
  541. if [ $? -eq 0 ]; then
  542. echo_success "nginx配置成功"
  543. return 0
  544. else
  545. echo_error "nginx配置失败"
  546. return 1
  547. fi
  548. }
  549. # 功能:在远程服务器上启动服务
  550. start_service() {
  551. echo_info "启动后端服务..."
  552. cat > ./start_service.exp << 'EOF'
  553. #!/usr/bin/expect -f
  554. set timeout 600
  555. set remote_dir [lindex $argv 0]
  556. set remote_user [lindex $argv 1]
  557. set remote_host [lindex $argv 2]
  558. set remote_pass [lindex $argv 3]
  559. set port [lindex $argv 4]
  560. spawn ssh $remote_user@$remote_host
  561. expect {
  562. "*yes/no*" {
  563. send "yes\r"
  564. exp_continue
  565. }
  566. "*password:*" {
  567. send "$remote_pass\r"
  568. }
  569. }
  570. expect "*#*"
  571. # 确保服务目录存在
  572. send "mkdir -p $remote_dir/backend\r"
  573. expect "*#*"
  574. # 检查后端文件是否存在
  575. send "echo '检查后端文件:' && ls -la $remote_dir/backend/\r"
  576. expect "*#*"
  577. # 编译 DHT11 C 读取器
  578. send "cd $remote_dir/backend && [ -f scripts/dht11_reader.c ] && (gcc -O2 -o scripts/dht11_reader scripts/dht11_reader.c -lgpiod && echo 'DHT11 C 读取器编译成功') || echo 'DHT11 C 读取器源码不存在,跳过编译'\r"
  579. expect "*#*"
  580. # 确保服务已经停止
  581. send "echo '停止旧服务进程...' && pkill -f 'python3 app.py' || echo '没有运行中的app.py进程'\r"
  582. expect "*#*"
  583. # 释放端口
  584. send "echo '释放端口...' && lsof -ti:$port | xargs -r kill -9 || echo '端口未被占用'\r"
  585. expect "*#*"
  586. sleep 2
  587. # 检查虚拟环境是否存在
  588. send "echo '检查虚拟环境:' && ls -la $remote_dir/venv/bin/activate\r"
  589. expect "*#*"
  590. # 启动后端服务(使用nohup在后台运行)
  591. send "cd $remote_dir/backend && source ../venv/bin/activate && [ -f /etc/default/dzxj_dtu ] && set -a && source /etc/default/dzxj_dtu && set +a && echo '已加载 DHT11 配置' && echo '正在启动服务...' && nohup python3 app.py > ./app_service.log 2>&1 &\r"
  592. expect "*#*"
  593. # 等待服务启动
  594. send "echo '等待服务启动...' && sleep 5\r"
  595. expect "*#*"
  596. # 检查服务是否启动成功
  597. send "echo '检查服务进程:' && ps aux | grep 'python3 app.py' | grep -v grep\r"
  598. expect "*#*"
  599. # 检查端口是否被占用
  600. send "echo '检查端口监听:' && (netstat -tulpn 2>/dev/null | grep :$port || ss -tulpn 2>/dev/null | grep :$port || echo '端口未监听')\r"
  601. expect "*#*"
  602. # 检查日志是否有错误
  603. send "echo '服务日志:' && tail -n 50 ./app_service.log\r"
  604. expect "*#*"
  605. # 测试API是否可以访问
  606. send "echo '测试API健康状态:' && curl -s http://localhost:$port/health || echo 'API当前不可访问'\r"
  607. expect "*#*"
  608. send "exit\r"
  609. expect eof
  610. EOF
  611. chmod +x ./start_service.exp
  612. ./start_service.exp "$REMOTE_DIR" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS" "$PORT"
  613. echo_success "服务启动操作完成,已添加详细日志和健康检查"
  614. }
  615. # 功能:检查服务状态
  616. check_service() {
  617. echo_info "检查服务状态..."
  618. cat > ./check_service.exp << EOF
  619. #!/usr/bin/expect -f
  620. set timeout 120
  621. spawn ssh $REMOTE_USER@$REMOTE_HOST
  622. expect {
  623. "*yes/no*" {
  624. send "yes\r"
  625. exp_continue
  626. }
  627. "*password:*" {
  628. send "$REMOTE_PASS\r"
  629. }
  630. }
  631. expect "*#*"
  632. send "echo '服务进程状态:'\r"
  633. expect "*#*"
  634. send "ps aux | grep 'python3 app.py' | grep -v grep\r"
  635. expect "*#*"
  636. send "echo '\n端口监听状态:'\r"
  637. expect "*#*"
  638. send "netstat -tulpn 2>/dev/null | grep :$PORT\r"
  639. expect "*#*"
  640. send "echo '\n网络接口信息:'\r"
  641. expect "*#*"
  642. send "ip addr show\r"
  643. expect "*#*"
  644. send "echo '\n测试API可用性:'\r"
  645. expect "*#*"
  646. send "curl -s http://localhost:$PORT/api/health || echo 'API不可访问'\r"
  647. expect "*#*"
  648. send "echo '\nDHT11 温湿度数据:'\r"
  649. expect "*#*"
  650. send "curl -s http://localhost:$PORT/api/sensor/env || echo '传感器API不可访问'\r"
  651. expect "*#*"
  652. send "exit\r"
  653. expect eof
  654. EOF
  655. chmod +x ./check_service.exp
  656. ./check_service.exp
  657. echo_success "服务状态检查完成"
  658. }
  659. # 功能:停止远程服务
  660. stop_service() {
  661. echo_info "停止后端服务..."
  662. cat > ./stop_service.exp << 'EOF'
  663. #!/usr/bin/expect -f
  664. set timeout 120
  665. spawn ssh [lindex $argv 0]@[lindex $argv 1]
  666. expect {
  667. "*yes/no*" {
  668. send "yes\r"
  669. exp_continue
  670. }
  671. "*password:*" {
  672. send "[lindex $argv 2]\r"
  673. }
  674. }
  675. expect "*#*"
  676. send "echo '停止服务进程...'\r"
  677. expect "*#*"
  678. send "pkill -f 'python3 app.py' || echo '未找到服务进程'\r"
  679. expect "*#*"
  680. send "sleep 2\r"
  681. expect "*#*"
  682. # 确认进程已停止
  683. send "ps aux | grep 'python3 app.py' | grep -v grep || echo '服务已停止'\r"
  684. expect "*#*"
  685. send "exit\r"
  686. expect eof
  687. EOF
  688. chmod +x ./stop_service.exp
  689. ./stop_service.exp "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS"
  690. echo_success "服务停止操作完成"
  691. }
  692. # 功能:远程诊断 DHT11 读取问题
  693. diagnose_dht11() {
  694. echo_info "远程诊断 DHT11 传感器..."
  695. cat > ./diagnose_dht11.exp << 'EOF'
  696. #!/usr/bin/expect -f
  697. set timeout 300
  698. set remote_dir [lindex $argv 0]
  699. set remote_user [lindex $argv 1]
  700. set remote_host [lindex $argv 2]
  701. set remote_pass [lindex $argv 3]
  702. set port [lindex $argv 4]
  703. spawn ssh $remote_user@$remote_host
  704. expect {
  705. "*yes/no*" {
  706. send "yes\r"
  707. exp_continue
  708. }
  709. "*password:*" {
  710. send "$remote_pass\r"
  711. }
  712. }
  713. expect "*#*"
  714. send "echo '===== /etc/default/dzxj_dtu ====='\r"
  715. expect "*#*"
  716. send "cat /etc/default/dzxj_dtu 2>/dev/null || echo '文件不存在'\r"
  717. expect "*#*"
  718. send "echo '===== gpioinfo 摘要 ====='\r"
  719. expect "*#*"
  720. send "gpioinfo | head -50\r"
  721. expect "*#*"
  722. send "echo '===== DHT11 探测测试 ====='\r"
  723. expect "*#*"
  724. send "cd $remote_dir/backend && source ../venv/bin/activate && python scripts/detect_dht11.py\r"
  725. expect {
  726. "DHT11_OK" {
  727. set dht11_ok 1
  728. }
  729. "DHT11_FAIL" {
  730. set dht11_ok 0
  731. }
  732. timeout {
  733. set dht11_ok 0
  734. }
  735. }
  736. expect "*#*"
  737. send "echo '===== 应用日志中的 DHT11 相关记录 ====='\r"
  738. expect "*#*"
  739. send "grep -i dht11 $remote_dir/backend/app_service.log 2>/dev/null | tail -30 || echo '未找到 DHT11 日志'\r"
  740. expect "*#*"
  741. send "echo '===== 传感器 API 返回值 ====='\r"
  742. expect "*#*"
  743. send "curl -s http://localhost:$port/api/sensor/env || echo 'API 不可访问'\r"
  744. expect "*#*"
  745. send "exit\r"
  746. expect eof
  747. EOF
  748. chmod +x ./diagnose_dht11.exp
  749. ./diagnose_dht11.exp "$REMOTE_DIR" "$REMOTE_USER" "$REMOTE_HOST" "$REMOTE_PASS" "$PORT"
  750. echo_info "诊断完成,请查看上方输出"
  751. }
  752. # 功能:检查系统依赖
  753. check_dependencies() {
  754. echo_info "检查系统依赖..."
  755. # 检查expect是否安装
  756. if ! command -v expect &> /dev/null; then
  757. echo_error "expect 命令未安装,请先安装: apt-get install expect 或 yum install expect"
  758. return 1
  759. fi
  760. # 已移除rsync检查,现在使用scp
  761. echo_success "系统依赖检查通过"
  762. return 0
  763. }
  764. # 显示帮助信息
  765. show_help() {
  766. echo "使用方法: $0 [选项]"
  767. echo ""
  768. echo "选项:"
  769. echo " --deploy 执行完整部署流程(检查、准备、上传、安装、启动、nginx配置)"
  770. echo " --start 仅启动服务"
  771. echo " --stop 仅停止服务"
  772. echo " --restart 重启服务"
  773. echo " --status 检查服务状态"
  774. echo " --release-port 释放占用的端口"
  775. echo " --install-deps 安装依赖"
  776. echo " --configure-nginx 配置nginx"
  777. echo " --check-ssh 检查SSH连接"
  778. echo " --diagnose-dht11 远程诊断 DHT11 读取问题"
  779. echo " --help 显示此帮助信息"
  780. echo ""
  781. echo "示例:"
  782. echo " $0 --deploy # 执行完整部署"
  783. echo " $0 --restart # 重启服务"
  784. echo " $0 --status # 检查服务状态"
  785. }
  786. # 主函数
  787. main() {
  788. if [ $# -eq 0 ]; then
  789. show_help
  790. exit 1
  791. fi
  792. # 检查系统依赖
  793. check_dependencies || exit 1
  794. case "$1" in
  795. --deploy)
  796. echo_info "开始完整部署流程..."
  797. check_ssh && \
  798. TEMP_DIR=$(prepare_files) && \
  799. upload_files "$TEMP_DIR" && \
  800. install_dependencies && \
  801. configure_dht11 && \
  802. release_port $PORT && \
  803. configure_nginx && \
  804. start_service && \
  805. check_service
  806. ;;
  807. --start)
  808. start_service
  809. ;;
  810. --stop)
  811. stop_service
  812. ;;
  813. --restart)
  814. stop_service && \
  815. release_port $PORT && \
  816. start_service && \
  817. check_service
  818. ;;
  819. --status)
  820. check_service
  821. ;;
  822. --release-port)
  823. release_port $PORT
  824. ;;
  825. --install-deps)
  826. install_dependencies
  827. ;;
  828. --configure-nginx)
  829. configure_nginx
  830. ;;
  831. --check-ssh)
  832. check_ssh
  833. ;;
  834. --diagnose-dht11)
  835. diagnose_dht11
  836. ;;
  837. --help)
  838. show_help
  839. exit 0
  840. ;;
  841. *)
  842. echo_error "未知选项: $1"
  843. show_help
  844. exit 1
  845. ;;
  846. esac
  847. # 清理临时文件
  848. if [ -d "$TEMP_DIR" ]; then
  849. rm -rf "$TEMP_DIR"
  850. fi
  851. rm -f ./*.exp
  852. echo_success "操作完成!"
  853. }
  854. # 执行主函数
  855. main "$@"