151 lines
5.0 KiB
Python
Executable File
151 lines
5.0 KiB
Python
Executable File
#!/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)
|