#!/usr/bin/env python3 """在新服务器安装CMD Agent + Node.js + 基础CI环境""" import subprocess import os import base64 NEW_SERVER = "172.30.18.199" KEY_CONTENT = """-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW QyNTUxOQAAACD6GquAk5vBEfbtaJCTSfnQEhjzC8e5GF60hSbPP0BJbAAAAJiQxGNokMRj aAAAAAtzc2gtZWQyNTUxOQAAACD6GquAk5vBEfbtaJCTSfnQEhjzC8e5GF60hSbPP0BJbA AAAED2muzuU4BAiCqbg0ayGxgiDvfS/xI1SFvb32oLzTnn8/oaq4CTm8ER9u1okJNJ+dAS GPMLx7kYXrSFJs8/QElsAAAAFHJ1bm5lci1hZG1pbkB4aWFveGlhAQ== -----END OPENSSH PRIVATE KEY----- """ key_path = "/tmp/new_server_ed25519" with open(key_path, "w") as f: f.write(KEY_CONTENT) os.chmod(key_path, 0o600) def ssh(cmd): r = subprocess.run( f'ssh -i {key_path} -o StrictHostKeyChecking=no -o ConnectTimeout=10 root@{NEW_SERVER} "{cmd}"', shell=True, capture_output=True, text=True ) return r.returncode, r.stdout.strip(), r.stderr.strip() print("=" * 50) print("步骤1: 环境检查") print("=" * 50) rc, out, err = ssh("cat /etc/os-release | head -3 && echo '---' && python3 --version && echo '---' && which docker && docker --version && echo '---' && which node 2>/dev/null && node --version 2>/dev/null || echo 'node: not installed'") print(out[:500]) print("\n" + "=" * 50) print("步骤2: 安装Node.js 20.x (CI checkout action需要)") print("=" * 50) rc, out, err = ssh("curl -fsSL https://deb.nodesource.com/setup_20.x | bash - 2>&1 | tail -3 && apt-get install -y nodejs 2>&1 | tail -3 && node --version && npm --version") print(f"结果: RC={rc}") print(out[:300]) if err and rc != 0: print(f"ERR: {err[:300]}") print("\n" + "=" * 50) print("步骤3: 安装flask (CMD Agent依赖)") print("=" * 50) # 先试pip install,如果失败试试--break-system-packages rc, out, err = ssh("pip3 install flask 2>&1 | tail -5") if rc != 0: print("pip3 install 失败,尝试 --break-system-packages...") rc, out, err = ssh("pip3 install --break-system-packages flask 2>&1 | tail -5") print(f"结果: RC={rc}") print(out[:300]) # 验证 rc2, out2, err2 = ssh("python3 -c 'import flask; print(flask.__version__)' 2>&1") print(f"flask验证: {out2[:100]}") print("\n" + "=" * 50) print("步骤4: 写入CMD Agent") print("=" * 50) agent_code = """#!/usr/bin/env python3 import subprocess from flask import Flask, request, jsonify app = Flask(__name__) API_KEY = "xiaoxia-cmd-agent-2026" @app.before_request def verify_key(): key = request.headers.get("X-API-Key", "") if key != API_KEY: return jsonify({"error": "unauthorized"}), 401 @app.route("/cmd", methods=["POST"]) def run_cmd(): data = request.get_json() cmd = data.get("cmd", "") timeout = data.get("timeout", 60) if not cmd: return jsonify({"error": "no cmd"}), 400 try: r = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=timeout) return jsonify({ "returncode": r.returncode, "stdout": r.stdout[:50000], "stderr": r.stderr[:50000] }) except subprocess.TimeoutExpired: return jsonify({"error": "timeout"}), 504 @app.route("/health", methods=["GET"]) def health(): return jsonify({"status": "ok", "service": "cmd-agent"}) if __name__ == "__main__": app.run(host="0.0.0.0", port=5927, debug=False) """ code_b64 = base64.b64encode(agent_code.encode()).decode() rc, out, err = ssh(f'mkdir -p /opt/cmd-agent && echo "{code_b64}" | base64 -d > /opt/cmd-agent/server.py && chmod +x /opt/cmd-agent/server.py && ls -la /opt/cmd-agent/') print(f"写入: {'成功' if rc==0 else '失败'}") print(out[:200]) print("\n" + "=" * 50) print("步骤5: 创建systemd服务") print("=" * 50) svc = """[Unit] Description=CMD Agent After=network.target [Service] Type=simple User=root WorkingDirectory=/opt/cmd-agent ExecStart=/usr/bin/python3 /opt/cmd-agent/server.py Restart=always RestartSec=5 [Install] WantedBy=multi-user.target """ svc_b64 = base64.b64encode(svc.encode()).decode() rc, out, err = ssh(f'echo "{svc_b64}" | base64 -d > /etc/systemd/system/cmd-agent.service && systemctl daemon-reload && systemctl enable cmd-agent.service && systemctl start cmd-agent.service && sleep 2 && systemctl is-active cmd-agent.service') print(f"服务状态: {out[:100] if rc==0 else '失败'}") if err and rc != 0: print(f"ERR: {err[:300]}") print("\n" + "=" * 50) print("步骤6: CMD Agent健康检查") print("=" * 50) rc, out, err = ssh("curl -s -H 'X-API-Key: xiaoxia-cmd-agent-2026' http://127.0.0.1:5927/health") print(f"健康检查: {out[:200]}") print("\n" + "=" * 50) print("步骤7: Docker镜像检查") print("=" * 50) rc, out, err = ssh("docker images 2>&1 | head -15") print(f"镜像:\n{out[:400]}") print("\n" + "=" * 50) print("步骤8: 最终环境核验") print("=" * 50) rc, out, err = ssh("echo 'Python:' && python3 --version && echo 'Node:' && node --version && echo 'Docker:' && docker --version && echo 'Git:' && git --version && echo 'Runner进程:' && ps aux | grep act_runner_v0.2.6 | grep -v grep | wc -l") print(out) print("\n" + "=" * 50) print("全部完成!") print("=" * 50)