mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-10-10 20:06:18 +00:00
Update flask_server.py
This commit is contained in:
@@ -319,14 +319,6 @@ def get_system_info():
|
||||
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
|
||||
@@ -1572,6 +1564,63 @@ def identify_fan(fan_name, adapter):
|
||||
|
||||
return fan_name
|
||||
|
||||
def get_gpu_info():
|
||||
"""Get GPU information using various tools (nvidia-smi, intel_gpu_top, radeontop)"""
|
||||
gpus = []
|
||||
try:
|
||||
# Get basic GPU info from lspci first
|
||||
result = subprocess.run(['lspci'], capture_output=True, text=True, timeout=5)
|
||||
if result.returncode == 0:
|
||||
for line in result.stdout.split('\n'):
|
||||
if any(keyword in line for keyword in ['VGA compatible controller', '3D controller', 'Display controller']):
|
||||
parts = line.split(':', 2)
|
||||
if len(parts) >= 3:
|
||||
gpu_name = parts[2].strip()
|
||||
slot = parts[0]
|
||||
|
||||
vendor = 'Unknown'
|
||||
if 'NVIDIA' in gpu_name or 'nVidia' in gpu_name:
|
||||
vendor = 'NVIDIA'
|
||||
elif 'AMD' in gpu_name or 'ATI' in gpu_name or 'Radeon' in gpu_name:
|
||||
vendor = 'AMD'
|
||||
elif 'Intel' in gpu_name:
|
||||
vendor = 'Intel'
|
||||
|
||||
gpu_data = {
|
||||
'name': gpu_name,
|
||||
'vendor': vendor,
|
||||
'slot': slot
|
||||
}
|
||||
|
||||
# Attempt to get detailed info based on vendor
|
||||
if vendor == 'NVIDIA':
|
||||
detailed_info = get_detailed_gpu_info(gpu_data)
|
||||
gpu_data.update(detailed_info)
|
||||
elif vendor == 'Intel':
|
||||
detailed_info = get_detailed_gpu_info(gpu_data)
|
||||
gpu_data.update(detailed_info)
|
||||
elif vendor == 'AMD':
|
||||
# Placeholder for AMD monitoring if radeontop is available and integrated
|
||||
try:
|
||||
check_result = subprocess.run(['which', 'radeontop'], capture_output=True, timeout=1)
|
||||
if check_result.returncode == 0:
|
||||
gpu_data['has_monitoring_tool'] = True
|
||||
else:
|
||||
gpu_data['has_monitoring_tool'] = False
|
||||
except Exception as e:
|
||||
print(f"[v0] Error checking for radeontop: {e}")
|
||||
gpu_data['has_monitoring_tool'] = False
|
||||
|
||||
gpus.append(gpu_data)
|
||||
print(f"[v0] Detected GPU: {gpu_name} ({vendor}) in slot {slot}")
|
||||
print(f"[v0] Total GPUs detected: {len(gpus)}")
|
||||
except Exception as e:
|
||||
print(f"[v0] Error getting GPU info: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
return gpus
|
||||
|
||||
def get_detailed_gpu_info(gpu):
|
||||
"""Get detailed GPU information using nvidia-smi, intel_gpu_top, or radeontop"""
|
||||
detailed_info = {}
|
||||
@@ -1588,7 +1637,7 @@ def get_detailed_gpu_info(gpu):
|
||||
else:
|
||||
print(f"[v0] intel_gpu_top found for Intel GPU")
|
||||
|
||||
gpu_device = '/dev/dri/card0'
|
||||
gpu_device = '/dev/dri/card0' # Assume first DRI card is the target
|
||||
if not os.path.exists(gpu_device):
|
||||
print(f"[v0] GPU device {gpu_device} not found - marking tool as unavailable")
|
||||
detailed_info['has_monitoring_tool'] = False
|
||||
@@ -1931,114 +1980,6 @@ def get_network_hardware_info(pci_slot):
|
||||
|
||||
return net_info
|
||||
|
||||
def get_gpu_info():
|
||||
"""Get GPU information from lspci and enrich with temperature/fan data from sensors"""
|
||||
gpus = []
|
||||
|
||||
try:
|
||||
result = subprocess.run(['lspci'], capture_output=True, text=True, timeout=5)
|
||||
if result.returncode == 0:
|
||||
for line in result.stdout.split('\n'):
|
||||
# Match VGA, 3D, Display controllers
|
||||
if any(keyword in line for keyword in ['VGA compatible controller', '3D controller', 'Display controller']):
|
||||
# Line format: "00:02.0 VGA compatible controller: Intel Corporation ..."
|
||||
# Split on first space to get slot, then split remaining on first colon to separate class from name
|
||||
parts = line.split(' ', 1)
|
||||
if len(parts) >= 2:
|
||||
slot = parts[0].strip() # Now captures full slot like "00:02.0"
|
||||
remaining = parts[1]
|
||||
|
||||
# Split remaining part to get GPU name (after the class description)
|
||||
if ':' in remaining:
|
||||
class_and_name = remaining.split(':', 1)
|
||||
gpu_name = class_and_name[1].strip() if len(class_and_name) > 1 else remaining.strip()
|
||||
else:
|
||||
gpu_name = remaining.strip()
|
||||
|
||||
# Determine vendor
|
||||
vendor = 'Unknown'
|
||||
if 'NVIDIA' in gpu_name or 'nVidia' in gpu_name:
|
||||
vendor = 'NVIDIA'
|
||||
elif 'AMD' in gpu_name or 'ATI' in gpu_name or 'Radeon' in gpu_name:
|
||||
vendor = 'AMD'
|
||||
elif 'Intel' in gpu_name:
|
||||
vendor = 'Intel'
|
||||
|
||||
gpu = {
|
||||
'slot': slot,
|
||||
'name': gpu_name,
|
||||
'vendor': vendor,
|
||||
'type': 'Discrete' if vendor in ['NVIDIA', 'AMD'] else 'Integrated'
|
||||
}
|
||||
|
||||
pci_info = get_pci_device_info(slot)
|
||||
if pci_info:
|
||||
gpu['pci_class'] = pci_info.get('class', '')
|
||||
gpu['pci_driver'] = pci_info.get('driver', '')
|
||||
gpu['pci_kernel_module'] = pci_info.get('kernel_module', '')
|
||||
|
||||
detailed_info = get_detailed_gpu_info(gpu)
|
||||
gpu.update(detailed_info)
|
||||
|
||||
gpus.append(gpu)
|
||||
print(f"[v0] Found GPU: {gpu_name} ({vendor}) at slot {slot}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[v0] Error detecting GPUs from lspci: {e}")
|
||||
|
||||
try:
|
||||
result = subprocess.run(['sensors'], capture_output=True, text=True, timeout=5)
|
||||
if result.returncode == 0:
|
||||
current_adapter = None
|
||||
|
||||
for line in result.stdout.split('\n'):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
|
||||
# Detect adapter line
|
||||
if line.startswith('Adapter:'):
|
||||
current_adapter = line.replace('Adapter:', '').strip()
|
||||
continue
|
||||
|
||||
# Look for GPU-related sensors (nouveau, amdgpu, radeon, i915)
|
||||
if ':' in line and not line.startswith(' '):
|
||||
parts = line.split(':', 1)
|
||||
sensor_name = parts[0].strip()
|
||||
value_part = parts[1].strip()
|
||||
|
||||
# Check if this is a GPU sensor
|
||||
gpu_sensor_keywords = ['nouveau', 'amdgpu', 'radeon', 'i915']
|
||||
is_gpu_sensor = any(keyword in current_adapter.lower() if current_adapter else False for keyword in gpu_sensor_keywords)
|
||||
|
||||
if is_gpu_sensor:
|
||||
# Try to match this sensor to a GPU
|
||||
for gpu in gpus:
|
||||
# Match nouveau to NVIDIA, amdgpu/radeon to AMD, i915 to Intel
|
||||
if (('nouveau' in current_adapter.lower() and gpu['vendor'] == 'NVIDIA') or
|
||||
(('amdgpu' in current_adapter.lower() or 'radeon' in current_adapter.lower()) and gpu['vendor'] == 'AMD') or
|
||||
('i915' in current_adapter.lower() and gpu['vendor'] == 'Intel')):
|
||||
|
||||
# Parse temperature (only if not already set by nvidia-smi)
|
||||
if 'temperature' not in gpu or gpu['temperature'] is None:
|
||||
if '°C' in value_part or 'C' in value_part:
|
||||
temp_match = re.search(r'([+-]?[\d.]+)\s*°?C', value_part)
|
||||
if temp_match:
|
||||
gpu['temperature'] = float(temp_match.group(1))
|
||||
print(f"[v0] GPU {gpu['name']}: Temperature = {gpu['temperature']}°C")
|
||||
|
||||
# Parse fan speed
|
||||
elif 'RPM' in value_part:
|
||||
rpm_match = re.search(r'([\d.]+)\s*RPM', value_part)
|
||||
if rpm_match:
|
||||
gpu['fan_speed'] = int(float(rpm_match.group(1)))
|
||||
gpu['fan_unit'] = 'RPM'
|
||||
print(f"[v0] GPU {gpu['name']}: Fan = {gpu['fan_speed']} RPM")
|
||||
except Exception as e:
|
||||
print(f"[v0] Error enriching GPU data from sensors: {e}")
|
||||
|
||||
return gpus
|
||||
|
||||
def get_disk_hardware_info(disk_name):
|
||||
"""Get detailed hardware information for a disk"""
|
||||
disk_info = {}
|
||||
@@ -2688,10 +2629,10 @@ def api_hardware():
|
||||
# Format data for frontend
|
||||
formatted_data = {
|
||||
'cpu': hardware_info.get('cpu', {}),
|
||||
'motherboard': hardware_info.get('motherboard', {}),
|
||||
'motherboard': hardware_data.get('motherboard', {}),
|
||||
'memory_modules': hardware_info.get('memory_modules', []),
|
||||
'storage_devices': hardware_info.get('storage_devices', []),
|
||||
'pci_devices': hardware_info.get('pci_devices', []),
|
||||
'pci_devices': hardware_info.get('pci_devices', []), # No filtering - include all PCI devices including GPUs
|
||||
'temperatures': hardware_info.get('sensors', {}).get('temperatures', []),
|
||||
'fans': all_fans, # Return combined fans (sensors + IPMI)
|
||||
'power_supplies': hardware_info.get('ipmi_power', {}).get('power_supplies', []),
|
||||
@@ -2715,29 +2656,47 @@ def api_hardware():
|
||||
def api_gpu_realtime(slot):
|
||||
"""Get real-time GPU monitoring data for a specific GPU"""
|
||||
try:
|
||||
# Find the GPU by slot
|
||||
hardware_info = get_hardware_info()
|
||||
gpus = hardware_info.get('gpus', [])
|
||||
print(f"[v0] Getting real-time data for GPU slot {slot}")
|
||||
gpus = get_gpu_info()
|
||||
|
||||
gpu = None
|
||||
for g in gpus:
|
||||
if g.get('slot') == slot or g.get('slot', '').startswith(slot):
|
||||
if g.get('slot') == slot:
|
||||
gpu = g
|
||||
break
|
||||
|
||||
if not gpu:
|
||||
print(f"[v0] GPU not found for slot {slot}")
|
||||
return jsonify({'error': 'GPU not found'}), 404
|
||||
|
||||
# Get real-time monitoring data
|
||||
realtime_data = get_detailed_gpu_info(gpu)
|
||||
# Extract only the monitoring-related fields
|
||||
realtime_data = {
|
||||
'has_monitoring_tool': gpu.get('has_monitoring_tool', False)
|
||||
}
|
||||
|
||||
# Add monitoring data if available
|
||||
monitoring_fields = [
|
||||
'temperature', 'power_draw', 'power_limit', 'utilization_gpu',
|
||||
'utilization_memory', 'clock_graphics', 'clock_memory', 'clock_max',
|
||||
'memory_total', 'memory_used', 'memory_free', 'fan_speed', 'fan_unit',
|
||||
'driver_version', 'pcie_gen', 'pcie_width', 'power_state', 'irq_rate',
|
||||
'engine_render', 'engine_blitter', 'engine_video', 'engine_video_enhance',
|
||||
'processes'
|
||||
]
|
||||
|
||||
for field in monitoring_fields:
|
||||
if field in gpu and gpu[field] is not None:
|
||||
realtime_data[field] = gpu[field]
|
||||
|
||||
print(f"[v0] /api/gpu/{slot}/realtime returning data")
|
||||
print(f"[v0] - Vendor: {gpu.get('vendor')}")
|
||||
print(f"[v0] - Realtime data: {realtime_data}")
|
||||
print(f"[v0] - Has monitoring tool: {realtime_data.get('has_monitoring_tool')}")
|
||||
|
||||
return jsonify(realtime_data)
|
||||
except Exception as e:
|
||||
print(f"[v0] Error getting real-time GPU data: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/api/vms/<int:vmid>', methods=['GET'])
|
||||
|
Reference in New Issue
Block a user