""" 快速部署问卷更新到 NAS """ import paramiko, base64, tarfile, io, time NAS_HOST = "100.85.152.112" NAS_PORT = 22 NAS_USER = "simon" NAS_PASS = "Nas82829330" NAS_DEPLOY_PATH = "/volume1/docker/gaokao-portal" DOCKER = f"echo '{NAS_PASS}' | sudo -S /usr/local/bin/docker" def run_cmd(client, cmd, desc="", timeout=30): if desc: print(f"[{desc}]") stdin, stdout, stderr = client.exec_command(cmd, timeout=timeout) out = stdout.read().decode("utf-8", errors="replace").strip() err = stderr.read().decode("utf-8", errors="replace").strip() status = stdout.channel.recv_exit_status() if out: for line in out.split("\n")[:5]: print(f" > {line}") if err and status != 0: for line in err.split("\n")[:3]: print(f" ! {line}") return out, err, status def run_stdin(client, cmd, data, desc=""): if desc: print(f"[{desc}]") transport = client.get_transport() ch = transport.open_session() ch.exec_command(cmd) ch.sendall(data) ch.shutdown_write() while not ch.exit_status_ready(): time.sleep(0.1) out = ch.recv(4096).decode() err = ch.recv_stderr(4096).decode() status = ch.recv_exit_status() print(f" 传输完成,退出码 {status}") return out, err, status # 打包 buf = io.BytesIO() with tarfile.open(fileobj=buf, mode="w:gz") as tar: tar.add("C:/Users/simon/WorkBuddy/2026-05-20-15-22-53/deploy/backend/seed_data.py", arcname="seed_data.py") tar_data = buf.getvalue() b64 = base64.b64encode(tar_data).decode("ascii") # 连接并部署 client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(NAS_HOST, NAS_PORT, NAS_USER, NAS_PASS) print("=" * 50) print("部署问卷更新") print("=" * 50) # 1. 上传 run_stdin(client, "base64 -d > /tmp/seed_data.py", b64, "上传") # 2. 备份并替换 run_cmd(client, f"cp {NAS_DEPLOY_PATH}/backend/seed_data.py {NAS_DEPLOY_PATH}/backend/seed_data.py.bak", "备份旧文件") run_cmd(client, f"cp /tmp/seed_data.py {NAS_DEPLOY_PATH}/backend/seed_data.py", "替换新文件") # 3. 重建容器(重新运行 seed) print("\n重建容器...") compose = f"{DOCKER} compose" run_cmd(client, f"cd {NAS_DEPLOY_PATH} && {compose} down", "停止容器") run_cmd(client, f"cd {NAS_DEPLOY_PATH} && {compose} up -d --build", "重新构建", timeout=120) # 4. 等待 print("\n等待容器启动...") for i in range(6): time.sleep(5) out, _, _ = run_cmd(client, f"cd {NAS_DEPLOY_PATH} && {compose} ps", f"检查 {i+1}/6") if "Up" in out: print(" 容器已启动!") break # 5. 验证 run_cmd(client, f"curl -s http://localhost:8080/api/questionnaires | head -100", "验证问卷API") # 6. 清理 run_cmd(client, "rm -f /tmp/seed_data.py", "清理") print("\n完成!刷新问卷页面查看新问卷。") client.close()