95 lines
3.5 KiB
Python
95 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Скрипт метрик для VPS: CPU, RAM, диск.
|
||
Запуск: python3 vps-metrics-api.py [--port 3497]
|
||
Установи на каждый VPS и открой порт в файрволе (3497/tcp).
|
||
|
||
Systemd (опционально):
|
||
sudo cp vps-metrics-api.py /usr/local/bin/
|
||
sudo chmod +x /usr/local/bin/vps-metrics-api.py
|
||
Создай юнит /etc/systemd/system/vps-metrics.service с ExecStart=/usr/bin/python3 /usr/local/bin/vps-metrics-api.py
|
||
sudo systemctl enable --now vps-metrics
|
||
"""
|
||
import json
|
||
import subprocess
|
||
import sys
|
||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||
|
||
PORT = 3497
|
||
|
||
|
||
def get_metrics():
|
||
"""Собирает метрики из /proc и df. Только stdlib."""
|
||
out = {}
|
||
try:
|
||
# Load average (1 min)
|
||
with open("/proc/loadavg") as f:
|
||
parts = f.read().strip().split()
|
||
out["load_1"] = round(float(parts[0]), 2)
|
||
# Memory: MemTotal, MemAvailable
|
||
mem = {}
|
||
with open("/proc/meminfo") as f:
|
||
for line in f:
|
||
if ":" in line:
|
||
k, v = line.strip().split(":", 1)
|
||
mem[k.strip()] = int(v.strip().split()[0]) # kB
|
||
total_kb = mem.get("MemTotal", 0)
|
||
avail_kb = mem.get("MemAvailable", mem.get("MemFree", 0))
|
||
used_kb = total_kb - avail_kb
|
||
out["memory_total_gb"] = round(total_kb / 1024 / 1024, 2)
|
||
out["memory_used_gb"] = round(used_kb / 1024 / 1024, 2)
|
||
out["memory_percent"] = round(100 * used_kb / total_kb, 1) if total_kb else 0
|
||
out["memory.status"] = f"{out['memory_used_gb']:.1f} / {out['memory_total_gb']:.1f} GB"
|
||
# Disk: root /
|
||
result = subprocess.run(
|
||
["df", "-k", "/"],
|
||
capture_output=True,
|
||
text=True,
|
||
timeout=5,
|
||
)
|
||
if result.returncode == 0 and result.stdout:
|
||
lines = result.stdout.strip().split("\n")
|
||
if len(lines) >= 2:
|
||
parts = lines[1].split()
|
||
if len(parts) >= 4:
|
||
total_kb = int(parts[1])
|
||
used_kb = int(parts[2])
|
||
avail_kb = int(parts[3])
|
||
total_gb = total_kb / 1024 / 1024
|
||
used_gb = used_kb / 1024 / 1024
|
||
avail_gb = avail_kb / 1024 / 1024
|
||
out["disk_total_gb"] = round(total_gb, 1)
|
||
out["disk_used_gb"] = round(used_gb, 1)
|
||
out["disk_free_gb"] = round(avail_gb, 1)
|
||
out["disk_percent"] = round(100 * used_kb / total_kb, 1) if total_kb else 0
|
||
out["disk.status"] = f"{out['disk_free_gb']:.1f} / {out['disk_total_gb']:.1f} GB свободно"
|
||
# Uptime
|
||
with open("/proc/uptime") as f:
|
||
out["uptime_seconds"] = int(float(f.read().split()[0]))
|
||
except Exception as e:
|
||
out["error"] = str(e)
|
||
return out
|
||
|
||
|
||
class Handler(BaseHTTPRequestHandler):
|
||
def do_GET(self):
|
||
self.send_response(200)
|
||
self.send_header("Content-Type", "application/json")
|
||
self.end_headers()
|
||
self.wfile.write(json.dumps(get_metrics(), ensure_ascii=False).encode())
|
||
|
||
def log_message(self, *args):
|
||
pass
|
||
|
||
|
||
def main():
|
||
port = PORT
|
||
if len(sys.argv) > 1 and sys.argv[1] == "--port" and len(sys.argv) > 2:
|
||
port = int(sys.argv[2])
|
||
print(f"VPS metrics API: http://0.0.0.0:{port}", file=sys.stderr)
|
||
HTTPServer(("0.0.0.0", port), Handler).serve_forever()
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|