diff --git a/AppImage/components/system-overview.tsx b/AppImage/components/system-overview.tsx
index 71bea5d..c72ea93 100644
--- a/AppImage/components/system-overview.tsx
+++ b/AppImage/components/system-overview.tsx
@@ -18,6 +18,7 @@ interface SystemData {
node_id: string
timestamp: string
cpu_cores?: number
+ cpu_threads?: number
proxmox_version?: string
kernel_version?: string
available_updates?: number
@@ -271,7 +272,7 @@ export function SystemOverview() {
}
fetchVMs()
- const vmInterval = setInterval(fetchVMs, 15000)
+ const vmInterval = setInterval(fetchVMs, 60000)
return () => {
clearInterval(vmInterval)
@@ -288,7 +289,7 @@ export function SystemOverview() {
}
fetchStorage()
- const storageInterval = setInterval(fetchStorage, 30000)
+ const storageInterval = setInterval(fetchStorage, 60000)
return () => {
clearInterval(storageInterval)
@@ -388,6 +389,44 @@ export function SystemOverview() {
(s) => s.name === "local-lvm" || s.name === "local-zfs" || s.name === "local",
)
+ const getLoadStatus = (load: number, cores: number) => {
+ if (load < cores) {
+ return { status: "Normal", color: "bg-green-500/10 text-green-500 border-green-500/20" }
+ } else if (load < cores * 1.5) {
+ return { status: "Moderate", color: "bg-yellow-500/10 text-yellow-500 border-yellow-500/20" }
+ } else {
+ return { status: "High", color: "bg-red-500/10 text-red-500 border-red-500/20" }
+ }
+ }
+
+ const systemAlerts = []
+ if (systemData.available_updates && systemData.available_updates > 0) {
+ systemAlerts.push({
+ type: "warning",
+ message: `${systemData.available_updates} updates available`,
+ })
+ }
+ if (vmStats.stopped > 0) {
+ systemAlerts.push({
+ type: "info",
+ message: `${vmStats.stopped} VM${vmStats.stopped > 1 ? "s" : ""} stopped`,
+ })
+ }
+ if (systemData.temperature > 75) {
+ systemAlerts.push({
+ type: "warning",
+ message: "High temperature detected",
+ })
+ }
+ if (localStorage && localStorage.percent > 90) {
+ systemAlerts.push({
+ type: "warning",
+ message: "System storage almost full",
+ })
+ }
+
+ const loadStatus = getLoadStatus(systemData.load_average[0], systemData.cpu_cores || 8)
+
return (
{/* Key Metrics Cards */}
@@ -637,37 +676,56 @@ export function SystemOverview() {
+ {/* System Health & Alerts */}
- Performance Metrics
+ System Health & Alerts
-
-
+
+
- Load Average:
- (1m, 5m, 15m)
+ Load Average (1m):
+
+
+
+ {systemData.load_average[0].toFixed(2)}
+
+
+ {loadStatus.status}
+
-
- {systemData.load_average.map((avg) => avg.toFixed(2)).join(", ")}
-
-
- Total Memory:
- {systemData.memory_total} GB
-
-
- Available Memory:
-
- {(systemData.memory_total - systemData.memory_used).toFixed(1)} GB
-
-
-
-
CPU Cores:
-
{systemData.cpu_cores || "N/A"}
+
+
+ CPU Threads:
+ {systemData.cpu_threads || "N/A"}
+
+ {systemAlerts.length > 0 && (
+
+
Recent Alerts:
+
+ {systemAlerts.map((alert, index) => (
+
+ ))}
+
+
+ )}
+
+ {systemAlerts.length === 0 && (
+
+
+
+ All systems operational
+
+
+ )}
diff --git a/AppImage/scripts/flask_server.py b/AppImage/scripts/flask_server.py
index be3af2d..c1bb706 100644
--- a/AppImage/scripts/flask_server.py
+++ b/AppImage/scripts/flask_server.py
@@ -21,6 +21,7 @@ import shutil # Added for shutil.which
import xml.etree.ElementTree as ET # Added for XML parsing
import math # Imported math for format_bytes function
import urllib.parse # Added for URL encoding
+import platform # Added for platform.release()
app = Flask(__name__)
CORS(app) # Enable CORS for Next.js frontend
@@ -38,6 +39,73 @@ def format_bytes(size_in_bytes):
s = round(size_in_bytes / p, 2)
return f"{s} {size_name[i]}"
+# Helper functions for system info
+def get_cpu_temperature():
+ """Get CPU temperature using psutil if available, otherwise return 0."""
+ temp = 0
+ try:
+ if hasattr(psutil, "sensors_temperatures"):
+ temps = psutil.sensors_temperatures()
+ if temps:
+ # Priority order for temperature sensors
+ sensor_priority = ['coretemp', 'cpu_thermal', 'acpi', 'thermal_zone']
+ for sensor_name in sensor_priority:
+ if sensor_name in temps and temps[sensor_name]:
+ temp = temps[sensor_name][0].current
+ break
+
+ # If no priority sensor found, use first available
+ if temp == 0:
+ for name, entries in temps.items():
+ if entries:
+ temp = entries[0].current
+ break
+ except Exception as e:
+ print(f"Warning: Error reading temperature sensors: {e}")
+ return temp
+
+def get_uptime():
+ """Get system uptime in a human-readable format."""
+ try:
+ boot_time = psutil.boot_time()
+ uptime_seconds = time.time() - boot_time
+ return str(timedelta(seconds=int(uptime_seconds)))
+ except Exception as e:
+ print(f"Warning: Error getting uptime: {e}")
+ return "N/A"
+
+def get_proxmox_version():
+ """Get Proxmox version if available."""
+ proxmox_version = None
+ try:
+ result = subprocess.run(['pveversion'], capture_output=True, text=True, timeout=5)
+ if result.returncode == 0:
+ # Parse output like "pve-manager/9.0.6/..."
+ version_line = result.stdout.strip().split('\n')[0]
+ if '/' in version_line:
+ proxmox_version = version_line.split('/')[1]
+ except FileNotFoundError:
+ print("Warning: pveversion command not found - Proxmox may not be installed.")
+ except Exception as e:
+ print(f"Warning: Error getting Proxmox version: {e}")
+ return proxmox_version
+
+def get_available_updates():
+ """Get the number of available package updates."""
+ available_updates = 0
+ try:
+ # Use apt list --upgradable to count available updates
+ result = subprocess.run(['apt', 'list', '--upgradable'], capture_output=True, text=True, timeout=10)
+ if result.returncode == 0:
+ # Count lines minus the header line
+ lines = result.stdout.strip().split('\n')
+ available_updates = max(0, len(lines) - 1)
+ except FileNotFoundError:
+ print("Warning: apt command not found - cannot check for updates.")
+ except Exception as e:
+ print(f"Warning: Error checking for updates: {e}")
+ return available_updates
+
# AGREGANDO FUNCIÓN PARA PARSEAR PROCESOS DE INTEL_GPU_TOP (SIN -J)
def get_intel_gpu_processes_from_text():
"""Parse processes from intel_gpu_top text output (more reliable than JSON)"""
@@ -385,118 +453,8 @@ def serve_images(filename):
print(f"Error serving image {filename}: {e}")
return '', 404
-def get_system_info():
- """Get basic system information"""
- try:
- cpu_percent = psutil.cpu_percent(interval=0.5)
-
- # Memory usage
- memory = psutil.virtual_memory()
-
- temp = 0
- try:
- if hasattr(psutil, "sensors_temperatures"):
- temps = psutil.sensors_temperatures()
- if temps:
- # Priority order for temperature sensors
- sensor_priority = ['coretemp', 'cpu_thermal', 'acpi', 'thermal_zone']
- for sensor_name in sensor_priority:
- if sensor_name in temps and temps[sensor_name]:
- temp = temps[sensor_name][0].current
- break
-
- # If no priority sensor found, use first available
- if temp == 0:
- for name, entries in temps.items():
- if entries:
- temp = entries[0].current
- break
- except Exception as e:
- print(f"Error reading temperature sensors: {e}")
- temp = 0 # Use 0 to indicate no temperature available
-
- # Uptime
- boot_time = psutil.boot_time()
- uptime_seconds = time.time() - boot_time
- uptime_str = str(timedelta(seconds=int(uptime_seconds)))
-
- # Load average
- load_avg = os.getloadavg() if hasattr(os, 'getloadavg') else [0, 0, 0]
-
- hostname = socket.gethostname()
- node_id = f"pve-{hostname}"
-
- proxmox_version = None
- try:
- result = subprocess.run(['pveversion'], capture_output=True, text=True, timeout=5)
- if result.returncode == 0:
- # Parse output like "pve-manager/9.0.6/..."
- version_line = result.stdout.strip().split('\n')[0]
- if '/' in version_line:
- proxmox_version = version_line.split('/')[1]
- except Exception as e:
- print(f"Note: pveversion not available: {e}")
-
- kernel_version = None
- try:
- result = subprocess.run(['uname', '-r'], capture_output=True, text=True, timeout=5)
- if result.returncode == 0:
- kernel_version = result.stdout.strip()
- except Exception as e:
- print(f"Note: uname not available: {e}")
-
- cpu_cores = psutil.cpu_count(logical=False) # Physical cores only
-
- available_updates = 0
- try:
- result = subprocess.run(['apt', 'list', '--upgradable'], capture_output=True, text=True, timeout=10)
- if result.returncode == 0:
- # Count lines minus header
- lines = result.stdout.strip().split('\n')
- available_updates = max(0, len(lines) - 1)
- except Exception as e:
- print(f"Note: apt list not available: {e}")
-
- # Try to get Proxmox node info if available
- try:
- result = subprocess.run(['pvesh', 'get', '/nodes', '--output-format', 'json'],
- capture_output=True, text=True, timeout=5)
- if result.returncode == 0:
- nodes = json.loads(result.stdout)
- if nodes and len(nodes) > 0:
- node_id = nodes[0].get('node', node_id)
- except Exception as e:
- print(f"Note: pvesh not available or failed: {e}")
- pass # Use default if pvesh not available
-
- response = {
- 'cpu_usage': round(cpu_percent, 1),
- 'memory_usage': round(memory.percent, 1),
- 'memory_total': round(memory.total / (1024**3), 1), # GB
- 'memory_used': round(memory.used / (1024**3), 1), # GB
- 'temperature': temp,
- 'uptime': uptime_str,
- 'load_average': list(load_avg),
- 'hostname': hostname,
- 'node_id': node_id,
- 'timestamp': datetime.now().isoformat(),
- 'cpu_cores': cpu_cores
- }
-
- if proxmox_version:
- response['proxmox_version'] = proxmox_version
- if kernel_version:
- response['kernel_version'] = kernel_version
- if available_updates > 0:
- response['available_updates'] = available_updates
-
- return response
- except Exception as e:
- print(f"Critical error getting system info: {e}")
- return {
- 'error': f'Unable to access system information: {str(e)}',
- 'timestamp': datetime.now().isoformat()
- }
+# Moved helper functions for system info up
+# def get_system_info(): ... (moved up)
def get_storage_info():
"""Get storage and disk information"""
@@ -3311,8 +3269,58 @@ def get_hardware_info():
@app.route('/api/system', methods=['GET'])
def api_system():
- """Get system information"""
- return jsonify(get_system_info())
+ """Get system information including CPU, memory, and temperature"""
+ try:
+ cpu_usage = psutil.cpu_percent(interval=0.5)
+
+ memory = psutil.virtual_memory()
+ memory_used_gb = memory.used / (1024 ** 3)
+ memory_total_gb = memory.total / (1024 ** 3)
+ memory_usage_percent = memory.percent
+
+ # Get temperature
+ temp = get_cpu_temperature()
+
+ # Get uptime
+ uptime = get_uptime()
+
+ # Get load average
+ load_avg = os.getloadavg()
+
+ # Get CPU cores
+ cpu_cores = psutil.cpu_count(logical=False)
+
+ cpu_threads = psutil.cpu_count(logical=True)
+
+ # Get Proxmox version
+ proxmox_version = get_proxmox_version()
+
+ # Get kernel version
+ kernel_version = platform.release()
+
+ # Get available updates
+ available_updates = get_available_updates()
+
+ return jsonify({
+ 'cpu_usage': round(cpu_usage, 1),
+ 'memory_usage': round(memory_usage_percent, 1),
+ 'memory_total': round(memory_total_gb, 1),
+ 'memory_used': round(memory_used_gb, 1),
+ 'temperature': temp,
+ 'uptime': uptime,
+ 'load_average': list(load_avg),
+ 'hostname': socket.gethostname(),
+ 'node_id': socket.gethostname(),
+ 'timestamp': datetime.now().isoformat(),
+ 'cpu_cores': cpu_cores,
+ 'cpu_threads': cpu_threads,
+ 'proxmox_version': proxmox_version,
+ 'kernel_version': kernel_version,
+ 'available_updates': available_updates
+ })
+ except Exception as e:
+ print(f"Error getting system info: {e}")
+ return jsonify({'error': str(e)}), 500
@app.route('/api/storage', methods=['GET'])
def api_storage():