diff --git a/.gitea/workflows/install-cmd-agent-saas.yml b/.gitea/workflows/install-cmd-agent-saas.yml new file mode 100644 index 000000000..1c0ecedf8 --- /dev/null +++ b/.gitea/workflows/install-cmd-agent-saas.yml @@ -0,0 +1,270 @@ +name: Install CMD Agent (saas label) + +on: + workflow_dispatch: + +jobs: + install-1: + name: Install CMD Agent - try 1 + runs-on: saas + steps: + - name: Install CMD Agent on host + run: | + echo "=== Environment ===" + echo "Hostname: $(hostname)" + echo "IPs: $(hostname -I)" + echo "Python: $(python3 --version)" + echo "Whoami: $(whoami)" + echo "" + + # 创建目录 + sudo mkdir -p /opt/xiaoxia-cmd-agent + + # 写入server.py + sudo tee /opt/xiaoxia-cmd-agent/server.py > /dev/null << 'PYEOF2' +import http.server +import subprocess +import json +import os +import secrets + +TOKEN_FILE = "/etc/xiaoxia-cmd-agent.token" +LOG_FILE = "/var/log/xiaoxia-cmd-agent.log" +LISTEN_HOST = "0.0.0.0" +LISTEN_PORT = 18888 + +def ensure_token(): + if not os.path.exists(TOKEN_FILE): + token = secrets.token_hex(16) + os.makedirs(os.path.dirname(TOKEN_FILE), exist_ok=True) + with open(TOKEN_FILE, "w") as f: + f.write(token) + os.chmod(TOKEN_FILE, 0o600) + with open(TOKEN_FILE) as f: + return f.read().strip() + +class CmdHandler(http.server.BaseHTTPRequestHandler): + def log_message(self, fmt, *args): + try: + with open(LOG_FILE, "a") as f: + f.write(f"{self.address_string()} - {fmt % args}\n") + except: + pass + + def do_POST(self): + if self.path == "/exec": + auth = self.headers.get("Authorization", "") + token = ensure_token() + if auth != f"xsa-{token}": + self.send_response(401) + self.end_headers() + self.wfile.write(b"Unauthorized") + return + length = int(self.headers.get("Content-Length", 0)) + body = json.loads(self.rfile.read(length)) + cmd = body.get("command", "") + timeout = body.get("timeout", 30) + try: + result = subprocess.run( + cmd, shell=True, capture_output=True, text=True, + timeout=timeout + ) + resp = { + "exit_code": result.returncode, + "stdout": result.stdout, + "stderr": result.stderr + } + except subprocess.TimeoutExpired: + resp = {"exit_code": -1, "stdout": "", "stderr": "timeout"} + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.end_headers() + self.wfile.write(json.dumps(resp).encode()) + elif self.path == "/status": + self.send_response(200) + self.send_header("Content-Type", "application/json") + self.end_headers() + self.wfile.write(json.dumps({"status": "ok", "version": "1.0"}).encode()) + else: + self.send_response(404) + self.end_headers() + +if __name__ == "__main__": + ensure_token() + server = http.server.HTTPServer((LISTEN_HOST, LISTEN_PORT), CmdHandler) + print(f"CMD Agent listening on {LISTEN_HOST}:{LISTEN_PORT}") + server.serve_forever() +PYEOF2 + + # 写入service文件 + sudo tee /etc/systemd/system/xiaoxia-cmd-agent.service > /dev/null << 'SVCEOF' +[Unit] +Description=Xiaoxia CMD Agent +After=network.target + +[Service] +Type=simple +ExecStart=/usr/bin/python3 /opt/xiaoxia-cmd-agent/server.py +Restart=always +RestartSec=5 + +[Install] +WantedBy=multi-user.target +SVCEOF + + # 启动服务 + sudo systemctl daemon-reload + sudo systemctl enable xiaoxia-cmd-agent + sudo systemctl restart xiaoxia-cmd-agent + + sleep 2 + + echo "=== Service Status ===" + sudo systemctl status xiaoxia-cmd-agent --no-pager | head -10 + + echo "" + echo "=== TOKEN ===" + sudo cat /etc/xiaoxia-cmd-agent.token + + echo "" + echo "=== Test /status ===" + curl -s http://127.0.0.1:18888/status + echo "" + + install-2: + name: Install CMD Agent - try 2 + runs-on: saas + steps: + - name: Install CMD Agent on host + run: | + echo "Hostname: $(hostname)" + echo "IPs: $(hostname -I)" + + sudo mkdir -p /opt/xiaoxia-cmd-agent + + sudo tee /opt/xiaoxia-cmd-agent/server.py > /dev/null << 'PYEOF2' +import http.server, subprocess, json, os, secrets + +TOKEN_FILE = "/etc/xiaoxia-cmd-agent.token" +LOG_FILE = "/var/log/xiaoxia-cmd-agent.log" + +def ensure_token(): + if not os.path.exists(TOKEN_FILE): + os.makedirs(os.path.dirname(TOKEN_FILE), exist_ok=True) + with open(TOKEN_FILE, "w") as f: + f.write(secrets.token_hex(16)) + os.chmod(TOKEN_FILE, 0o600) + with open(TOKEN_FILE) as f: + return f.read().strip() + +class CmdHandler(http.server.BaseHTTPRequestHandler): + def log_message(self, fmt, *args): + pass + def do_POST(self): + if self.path == "/exec": + auth = self.headers.get("Authorization", "") + if auth != f"xsa-{ensure_token()}": + self.send_response(401); self.end_headers(); return + length = int(self.headers.get("Content-Length", 0)) + body = json.loads(self.rfile.read(length)) + try: + r = subprocess.run(body.get("command",""), shell=True, capture_output=True, text=True, timeout=body.get("timeout",30)) + resp = {"exit_code": r.returncode, "stdout": r.stdout, "stderr": r.stderr} + except subprocess.TimeoutExpired: + resp = {"exit_code": -1, "stdout": "", "stderr": "timeout"} + self.send_response(200); self.send_header("Content-Type", "application/json"); self.end_headers() + self.wfile.write(json.dumps(resp).encode()) + elif self.path == "/status": + self.send_response(200); self.send_header("Content-Type", "application/json"); self.end_headers() + self.wfile.write(json.dumps({"status":"ok"}).encode()) + else: + self.send_response(404); self.end_headers() + +if __name__ == "__main__": + ensure_token() + http.server.HTTPServer(("0.0.0.0", 18888), CmdHandler).serve_forever() +PYEOF2 + + sudo tee /etc/systemd/system/xiaoxia-cmd-agent.service > /dev/null << 'SVCEOF' +[Unit] +Description=Xiaoxia CMD Agent +After=network.target +[Service] +Type=simple +ExecStart=/usr/bin/python3 /opt/xiaoxia-cmd-agent/server.py +Restart=always +RestartSec=5 +[Install] +WantedBy=multi-user.target +SVCEOF + + sudo systemctl daemon-reload + sudo systemctl enable xiaoxia-cmd-agent + sudo systemctl restart xiaoxia-cmd-agent + sleep 2 + echo "=== Status ===" + sudo systemctl is-active xiaoxia-cmd-agent + echo "=== Token ===" + sudo cat /etc/xiaoxia-cmd-agent.token + echo "=== Test ===" + curl -s http://127.0.0.1:18888/status + + install-3: + name: Install CMD Agent - try 3 + runs-on: saas + steps: + - name: Install CMD Agent on host + run: | + echo "Hostname: $(hostname)" + echo "IPs: $(hostname -I)" + sudo mkdir -p /opt/xiaoxia-cmd-agent + sudo tee /opt/xiaoxia-cmd-agent/server.py > /dev/null << 'PYEOF2' +import http.server, subprocess, json, os, secrets +TOKEN_FILE = "/etc/xiaoxia-cmd-agent.token" +def ensure_token(): + if not os.path.exists(TOKEN_FILE): + os.makedirs(os.path.dirname(TOKEN_FILE), exist_ok=True) + with open(TOKEN_FILE, "w") as f: f.write(secrets.token_hex(16)) + os.chmod(TOKEN_FILE, 0o600) + return open(TOKEN_FILE).read().strip() +class H(http.server.BaseHTTPRequestHandler): + def log_message(self, *a): pass + def do_POST(self): + if self.path == "/exec": + if self.headers.get("Authorization","") != f"xsa-{ensure_token()}": + self.send_response(401); self.end_headers(); return + b = json.loads(self.rfile.read(int(self.headers.get("Content-Length",0)))) + try: + r = subprocess.run(b.get("command",""), shell=True, capture_output=True, text=True, timeout=b.get("timeout",30)) + resp = {"exit_code": r.returncode, "stdout": r.stdout, "stderr": r.stderr} + except subprocess.TimeoutExpired: + resp = {"exit_code": -1, "stdout": "", "stderr": "timeout"} + self.send_response(200); self.send_header("Content-Type","application/json"); self.end_headers() + self.wfile.write(json.dumps(resp).encode()) + elif self.path == "/status": + self.send_response(200); self.send_header("Content-Type","application/json"); self.end_headers() + self.wfile.write(b'{"status":"ok"}') + else: + self.send_response(404); self.end_headers() +if __name__ == "__main__": + ensure_token() + http.server.HTTPServer(("0.0.0.0", 18888), H).serve_forever() +PYEOF2 + sudo tee /etc/systemd/system/xiaoxia-cmd-agent.service > /dev/null << 'SVCEOF' +[Unit] +Description=Xiaoxia CMD Agent +After=network.target +[Service] +Type=simple +ExecStart=/usr/bin/python3 /opt/xiaoxia-cmd-agent/server.py +Restart=always +RestartSec=5 +[Install] +WantedBy=multi-user.target +SVCEOF + sudo systemctl daemon-reload + sudo systemctl enable --now xiaoxia-cmd-agent + sleep 2 + echo "Active: $(systemctl is-active xiaoxia-cmd-agent)" + echo "Token: $(sudo cat /etc/xiaoxia-cmd-agent.token)" + echo "Test: $(curl -s http://127.0.0.1:18888/status)"