mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-11-18 11:36:17 +00:00
Update AppImage
This commit is contained in:
@@ -72,6 +72,9 @@ interface ProxmoxStorageData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const formatStorage = (sizeInGB: number): string => {
|
const formatStorage = (sizeInGB: number): string => {
|
||||||
|
if (sizeInGB <= 0) {
|
||||||
|
return "0 GB"
|
||||||
|
}
|
||||||
if (sizeInGB < 1) {
|
if (sizeInGB < 1) {
|
||||||
// Less than 1 GB, show in MB
|
// Less than 1 GB, show in MB
|
||||||
return `${(sizeInGB * 1024).toFixed(1)} MB`
|
return `${(sizeInGB * 1024).toFixed(1)} MB`
|
||||||
@@ -355,7 +358,9 @@ export function StorageOverview() {
|
|||||||
: 0
|
: 0
|
||||||
|
|
||||||
const usagePercent =
|
const usagePercent =
|
||||||
storageData.total > 0 ? ((totalProxmoxUsed / (storageData.total * 1024)) * 100).toFixed(2) : "0.00"
|
storageData.total > 0 && totalProxmoxUsed > 0
|
||||||
|
? ((totalProxmoxUsed / (storageData.total * 1024)) * 100).toFixed(2)
|
||||||
|
: "0.00"
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
|||||||
@@ -529,8 +529,9 @@ def serve_images(filename):
|
|||||||
# Moved helper functions for system info up
|
# Moved helper functions for system info up
|
||||||
# def get_system_info(): ... (moved up)
|
# def get_system_info(): ... (moved up)
|
||||||
|
|
||||||
|
# get_storage_info() function is OPTIMIZED to remove SMART data
|
||||||
def get_storage_info():
|
def get_storage_info():
|
||||||
"""Get storage and disk information"""
|
"""Get storage and disk information - OPTIMIZED: Basic info only, no SMART data"""
|
||||||
try:
|
try:
|
||||||
storage_data = {
|
storage_data = {
|
||||||
'total': 0,
|
'total': 0,
|
||||||
@@ -567,10 +568,9 @@ def get_storage_info():
|
|||||||
|
|
||||||
total_disk_size_bytes += disk_size_bytes
|
total_disk_size_bytes += disk_size_bytes
|
||||||
|
|
||||||
# Get SMART data for this disk
|
print(f"[v0] Getting basic info for {disk_name}...")
|
||||||
print(f"[v0] Getting SMART data for {disk_name}...")
|
basic_info = get_basic_disk_info(disk_name)
|
||||||
smart_data = get_smart_data(disk_name)
|
print(f"[v0] Basic info for {disk_name}: {basic_info}")
|
||||||
print(f"[v0] SMART data for {disk_name}: {smart_data}")
|
|
||||||
|
|
||||||
disk_size_kb = disk_size_bytes / 1024
|
disk_size_kb = disk_size_bytes / 1024
|
||||||
|
|
||||||
@@ -581,29 +581,17 @@ def get_storage_info():
|
|||||||
|
|
||||||
physical_disks[disk_name] = {
|
physical_disks[disk_name] = {
|
||||||
'name': disk_name,
|
'name': disk_name,
|
||||||
'size': disk_size_kb, # In KB for formatMemory() in Storage Summary
|
'size': disk_size_kb,
|
||||||
'size_formatted': size_str, # Added formatted size string for Storage section
|
'size_formatted': size_str,
|
||||||
'size_bytes': disk_size_bytes,
|
'size_bytes': disk_size_bytes,
|
||||||
'temperature': smart_data.get('temperature', 0),
|
'temperature': basic_info.get('temperature', 0),
|
||||||
'health': smart_data.get('health', 'unknown'),
|
'health': basic_info.get('health', 'unknown'),
|
||||||
'power_on_hours': smart_data.get('power_on_hours', 0),
|
'model': basic_info.get('model', 'Unknown'),
|
||||||
'smart_status': smart_data.get('smart_status', 'unknown'),
|
'rotation_rate': basic_info.get('rotation_rate', 0),
|
||||||
'model': smart_data.get('model', 'Unknown'),
|
|
||||||
'serial': smart_data.get('serial', 'Unknown'),
|
|
||||||
'reallocated_sectors': smart_data.get('reallocated_sectors', 0),
|
|
||||||
'pending_sectors': smart_data.get('pending_sectors', 0),
|
|
||||||
'crc_errors': smart_data.get('crc_errors', 0),
|
|
||||||
'rotation_rate': smart_data.get('rotation_rate', 0), # Added
|
|
||||||
'power_cycles': smart_data.get('power_cycles', 0), # Added
|
|
||||||
'percentage_used': smart_data.get('percentage_used'), # Added
|
|
||||||
'media_wearout_indicator': smart_data.get('media_wearout_indicator'), # Added
|
|
||||||
'wear_leveling_count': smart_data.get('wear_leveling_count'), # Added
|
|
||||||
'total_lbas_written': smart_data.get('total_lbas_written'), # Added
|
|
||||||
'ssd_life_left': smart_data.get('ssd_life_left') # Added
|
|
||||||
}
|
}
|
||||||
|
|
||||||
storage_data['disk_count'] += 1
|
storage_data['disk_count'] += 1
|
||||||
health = smart_data.get('health', 'unknown').lower()
|
health = basic_info.get('health', 'unknown').lower()
|
||||||
if health == 'healthy':
|
if health == 'healthy':
|
||||||
storage_data['healthy_disks'] += 1
|
storage_data['healthy_disks'] += 1
|
||||||
elif health == 'warning':
|
elif health == 'warning':
|
||||||
@@ -704,6 +692,57 @@ def get_storage_info():
|
|||||||
'critical_disks': 0
|
'critical_disks': 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# New function to get basic disk info quickly
|
||||||
|
def get_basic_disk_info(disk_name):
|
||||||
|
"""Get basic disk info quickly without full SMART scan - OPTIMIZED"""
|
||||||
|
basic_info = {
|
||||||
|
'temperature': 0,
|
||||||
|
'health': 'unknown',
|
||||||
|
'model': 'Unknown',
|
||||||
|
'rotation_rate': 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Only get basic info (-i) and health (-H), skip full attributes scan
|
||||||
|
cmd = ['smartctl', '-i', '-H', '-j', f'/dev/{disk_name}']
|
||||||
|
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=5)
|
||||||
|
|
||||||
|
if result.returncode in [0, 4]: # 0 = success, 4 = some SMART values exceeded threshold
|
||||||
|
try:
|
||||||
|
data = json.loads(result.stdout)
|
||||||
|
|
||||||
|
# Extract model
|
||||||
|
if 'model_name' in data:
|
||||||
|
basic_info['model'] = data['model_name']
|
||||||
|
elif 'model_family' in data:
|
||||||
|
basic_info['model'] = data['model_family']
|
||||||
|
|
||||||
|
# Extract rotation rate
|
||||||
|
if 'rotation_rate' in data:
|
||||||
|
basic_info['rotation_rate'] = data['rotation_rate']
|
||||||
|
|
||||||
|
# Extract SMART status
|
||||||
|
if 'smart_status' in data and 'passed' in data['smart_status']:
|
||||||
|
basic_info['health'] = 'healthy' if data['smart_status']['passed'] else 'critical'
|
||||||
|
|
||||||
|
# Extract temperature (quick check)
|
||||||
|
if 'temperature' in data and 'current' in data['temperature']:
|
||||||
|
basic_info['temperature'] = data['temperature']['current']
|
||||||
|
elif 'nvme_smart_health_information_log' in data:
|
||||||
|
nvme_data = data['nvme_smart_health_information_log']
|
||||||
|
if 'temperature' in nvme_data:
|
||||||
|
basic_info['temperature'] = nvme_data['temperature']
|
||||||
|
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[v0] Error getting basic disk info for {disk_name}: {e}")
|
||||||
|
|
||||||
|
return basic_info
|
||||||
|
|
||||||
|
|
||||||
def get_smart_data(disk_name):
|
def get_smart_data(disk_name):
|
||||||
"""Get SMART data for a specific disk - Enhanced with multiple device type attempts"""
|
"""Get SMART data for a specific disk - Enhanced with multiple device type attempts"""
|
||||||
smart_data = {
|
smart_data = {
|
||||||
@@ -2018,7 +2057,7 @@ def get_detailed_gpu_info(gpu):
|
|||||||
if 'clients' in json_data:
|
if 'clients' in json_data:
|
||||||
client_count = len(json_data['clients'])
|
client_count = len(json_data['clients'])
|
||||||
print(f"[v0] *** FOUND CLIENTS SECTION with {client_count} client(s) ***", flush=True)
|
print(f"[v0] *** FOUND CLIENTS SECTION with {client_count} client(s) ***", flush=True)
|
||||||
for client_id, client_data in json_data['clients'].items():
|
for client_id, client_data in json_data['clients']:
|
||||||
client_name = client_data.get('name', 'Unknown')
|
client_name = client_data.get('name', 'Unknown')
|
||||||
client_pid = client_data.get('pid', 'Unknown')
|
client_pid = client_data.get('pid', 'Unknown')
|
||||||
print(f"[v0] - Client: {client_name} (PID: {client_pid})", flush=True)
|
print(f"[v0] - Client: {client_name} (PID: {client_pid})", flush=True)
|
||||||
@@ -2524,7 +2563,7 @@ def get_detailed_gpu_info(gpu):
|
|||||||
mem_clock = clocks['GFX_MCLK']
|
mem_clock = clocks['GFX_MCLK']
|
||||||
if 'value' in mem_clock:
|
if 'value' in mem_clock:
|
||||||
detailed_info['clock_memory'] = f"{mem_clock['value']} MHz"
|
detailed_info['clock_memory'] = f"{mem_clock['value']} MHz"
|
||||||
print(f"[v0] Memory Clock: {detailed_info['clock_memory']} MHz", flush=True)
|
print(f"[v0] Memory Clock: {detailed_info['clock_memory']}", flush=True)
|
||||||
data_retrieved = True
|
data_retrieved = True
|
||||||
|
|
||||||
# Parse GPU activity (gpu_activity.GFX)
|
# Parse GPU activity (gpu_activity.GFX)
|
||||||
@@ -3573,9 +3612,20 @@ def api_system():
|
|||||||
|
|
||||||
@app.route('/api/storage', methods=['GET'])
|
@app.route('/api/storage', methods=['GET'])
|
||||||
def api_storage():
|
def api_storage():
|
||||||
"""Get storage information"""
|
"""Get storage information - OPTIMIZED: Basic info only"""
|
||||||
return jsonify(get_storage_info())
|
return jsonify(get_storage_info())
|
||||||
|
|
||||||
|
@app.route('/api/storage/disk/<disk_name>/details', methods=['GET'])
|
||||||
|
def api_disk_details(disk_name):
|
||||||
|
"""Get detailed SMART data for a specific disk - loaded on demand"""
|
||||||
|
try:
|
||||||
|
print(f"[v0] Getting detailed SMART data for {disk_name}...")
|
||||||
|
smart_data = get_smart_data(disk_name)
|
||||||
|
return jsonify(smart_data)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[v0] Error getting disk details: {e}")
|
||||||
|
return jsonify({'error': str(e)}), 500
|
||||||
|
|
||||||
@app.route('/api/proxmox-storage', methods=['GET'])
|
@app.route('/api/proxmox-storage', methods=['GET'])
|
||||||
def api_proxmox_storage():
|
def api_proxmox_storage():
|
||||||
"""Get Proxmox storage information"""
|
"""Get Proxmox storage information"""
|
||||||
@@ -4461,6 +4511,7 @@ def api_info():
|
|||||||
'/api/system',
|
'/api/system',
|
||||||
'/api/system-info',
|
'/api/system-info',
|
||||||
'/api/storage',
|
'/api/storage',
|
||||||
|
'/api/storage/disk/<disk_name>/details', # Added endpoint for detailed disk SMART data
|
||||||
'/api/proxmox-storage',
|
'/api/proxmox-storage',
|
||||||
'/api/network',
|
'/api/network',
|
||||||
'/api/vms',
|
'/api/vms',
|
||||||
@@ -4734,6 +4785,6 @@ if __name__ == '__main__':
|
|||||||
cli.show_server_banner = lambda *x: None
|
cli.show_server_banner = lambda *x: None
|
||||||
|
|
||||||
# Print only essential information
|
# Print only essential information
|
||||||
print("API endpoints available at: /api/system, /api/system-info, /api/storage, /api/proxmox-storage, /api/network, /api/vms, /api/logs, /api/health, /api/hardware, /api/prometheus")
|
print("API endpoints available at: /api/system, /api/system-info, /api/storage, /api/storage/disk/<disk_name>/details, /api/proxmox-storage, /api/network, /api/vms, /api/logs, /api/health, /api/hardware, /api/gpu/<slot>/realtime, /api/prometheus")
|
||||||
|
|
||||||
app.run(host='0.0.0.0', port=8008, debug=False)
|
app.run(host='0.0.0.0', port=8008, debug=False)
|
||||||
|
|||||||
Reference in New Issue
Block a user