diff --git a/platform/modules/backups.py b/platform/modules/backups.py index 6b38b91..23b2cd6 100644 --- a/platform/modules/backups.py +++ b/platform/modules/backups.py @@ -588,42 +588,53 @@ def get_all_stats(): # ──────────────────────────────────────────────────────────────── -# SYSTEM INFO — single batched SSH call +# SYSTEM INFO # ──────────────────────────────────────────────────────────────── def get_system_info(): if RUNNING_ON_MAIN_SERVER: - # Read directly from /proc (works in container with host /proc) try: - # CPU - with open('/proc/stat') as f: - cpu = f.readline().split() - idle = int(cpu[4]) - total = sum(int(x) for x in cpu[1:]) - cpu_pct = round(100 * (1 - idle/total), 1) if total else 0 + import time - # Memory + # ── CPU — two reads with delta (single snapshot always gives ~0%) ── + def _read_cpu(): + with open('/proc/stat') as f: + fields = f.readline().split() + idle = int(fields[4]) + total = sum(int(x) for x in fields[1:]) + return idle, total + + idle1, total1 = _read_cpu() + time.sleep(0.5) + idle2, total2 = _read_cpu() + + idle_delta = idle2 - idle1 + total_delta = total2 - total1 + cpu_pct = round(100 * (1 - idle_delta / total_delta), 1) if total_delta else 0.0 + + # ── Memory ────────────────────────────────────────────────────────── mem = {} with open('/proc/meminfo') as f: for line in f: - k, v = line.split(':') - mem[k.strip()] = int(v.strip().split()[0]) + parts = line.split(':') + if len(parts) == 2: + mem[parts[0].strip()] = int(parts[1].strip().split()[0]) mem_total_mb = mem['MemTotal'] // 1024 mem_used_mb = (mem['MemTotal'] - mem['MemAvailable']) // 1024 mem_pct = round(100 * mem_used_mb / mem_total_mb) if mem_total_mb else 0 - # Disk + # ── Disk ───────────────────────────────────────────────────────────── import shutil - disk = shutil.disk_usage('/') + disk = shutil.disk_usage('/') disk_used_gb = round(disk.used / 1024**3, 1) disk_total_gb = round(disk.total / 1024**3, 1) disk_pct = round(100 * disk.used / disk.total) - # Load + # ── Load ───────────────────────────────────────────────────────────── with open('/proc/loadavg') as f: load = f.read().split()[:3] - # Uptime + # ── Uptime ─────────────────────────────────────────────────────────── with open('/proc/uptime') as f: secs = int(float(f.read().split()[0])) days = secs // 86400 @@ -631,7 +642,7 @@ def get_system_info(): mins = (secs % 3600) // 60 uptime = f"up {days}d {hrs}h {mins}m" if days else f"up {hrs}h {mins}m" - # Docker version + # ── Docker version + hostname ───────────────────────────────────────── docker_v, _ = _run("docker --version 2>/dev/null | cut -d' ' -f3 | tr -d ','") hostname, _ = _run("cat /proc/sys/kernel/hostname 2>/dev/null || hostname") @@ -647,4 +658,39 @@ def get_system_info(): 'hostname': hostname.strip() or 'main server', } except Exception as e: - pass # fall through to SSH method \ No newline at end of file + print(f"[system_info] /proc read failed: {e}") + # fall through to SSH method below + + # ── Fallback: SSH to main server (used when RUNNING_ON_MAIN_SERVER = False) ── + cmd = ( + "CPU=$(top -bn2 -d0.5 | grep 'Cpu(s)' | tail -1 | " + "awk '{print 100 - $8}' 2>/dev/null || echo 'N/A'); " + "MEM=$(free -m | awk 'NR==2{printf \"%s/%sMB\", $3, $2}'); " + "MEM_PCT=$(free -m | awk 'NR==2{printf \"%d\", $3/$2*100}'); " + "DISK=$(df -h / | awk 'NR==2{print $3\"/\"$2}'); " + "DISK_PCT=$(df / | awk 'NR==2{print $5}' | tr -d '%'); " + "LOAD=$(cat /proc/loadavg | awk '{print $1, $2, $3}'); " + "UPTIME=$(uptime -p 2>/dev/null || uptime); " + "DOCKER=$(docker --version 2>/dev/null | cut -d' ' -f3 | tr -d ','); " + "HOST=$(hostname); " + "echo \"$CPU|$MEM|$MEM_PCT|$DISK|$DISK_PCT|$LOAD|$UPTIME|$DOCKER|$HOST\"" + ) + stdout, stderr = _ssh_main(cmd, timeout=20) + if not stdout: + return {} + + parts = stdout.split('|') + if len(parts) < 9: + return {} + + return { + 'cpu_pct': parts[0].strip(), + 'memory': parts[1].strip(), + 'mem_pct': parts[2].strip(), + 'disk': parts[3].strip(), + 'disk_pct': parts[4].strip(), + 'load': parts[5].strip(), + 'uptime': parts[6].strip(), + 'docker_v': parts[7].strip() or 'N/A', + 'hostname': parts[8].strip() or 'main server', + } \ No newline at end of file