chore: add saas-label cmd agent installer

This commit is contained in:
2026-07-13 16:54:11 +08:00
parent 403ddcfae4
commit 634cfe202d
+270
View File
@@ -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)"