Update health monitor

This commit is contained in:
MacRimi
2026-03-15 18:12:42 +01:00
parent af61d145da
commit 785d58cb59
3 changed files with 116 additions and 1 deletions

View File

@@ -179,6 +179,66 @@ def get_full_health():
except Exception as e:
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/cleanup-orphans', methods=['POST'])
def cleanup_orphan_errors():
"""
Clean up errors for devices that no longer exist in the system.
Useful when USB drives or temporary devices are disconnected.
"""
import os
import re
try:
cleaned = []
# Get all active disk errors
disk_errors = health_persistence.get_active_errors(category='disks')
for err in disk_errors:
err_key = err.get('error_key', '')
details = err.get('details', {})
if isinstance(details, str):
try:
import json as _json
details = _json.loads(details)
except Exception:
details = {}
device = details.get('device', '')
base_disk = details.get('disk', '')
# Try to determine the device path
dev_path = None
if base_disk:
dev_path = f'/dev/{base_disk}'
elif device:
dev_path = device if device.startswith('/dev/') else f'/dev/{device}'
elif err_key.startswith('disk_'):
# Extract device from error_key
dev_name = err_key.replace('disk_fs_', '').replace('disk_', '')
dev_name = re.sub(r'_.*$', '', dev_name) # Remove suffix
if dev_name:
dev_path = f'/dev/{dev_name}'
if dev_path:
# Also check base disk (remove partition number)
base_path = re.sub(r'\d+$', '', dev_path)
if not os.path.exists(dev_path) and not os.path.exists(base_path):
health_persistence.resolve_error(err_key, 'Device no longer present (manual cleanup)')
cleaned.append({'error_key': err_key, 'device': dev_path})
# Also cleanup disk_observations for non-existent devices
try:
health_persistence.cleanup_orphan_observations()
except Exception:
pass
return jsonify({
'success': True,
'cleaned_count': len(cleaned),
'cleaned_errors': cleaned
})
except Exception as e:
return jsonify({'error': str(e)}), 500
@health_bp.route('/api/health/pending-notifications', methods=['GET'])
def get_pending_notifications():
"""

View File

@@ -2093,7 +2093,21 @@ class HealthMonitor:
# Check if the device still exists. If not, auto-resolve
# the error -- it was likely a disconnected USB/temp device.
dev_path = f'/dev/{base_disk}' if base_disk else device
if not os.path.exists(dev_path):
# Also extract base disk from partition (e.g., sdb1 -> sdb)
if not base_disk and device:
# Remove /dev/ prefix and partition number
dev_name = device.replace('/dev/', '')
base_disk = re.sub(r'\d+$', '', dev_name) # sdb1 -> sdb
if base_disk:
dev_path = f'/dev/{base_disk}'
# Check both the specific device and the base disk
device_exists = os.path.exists(dev_path)
if not device_exists and device and device != dev_path:
device_exists = os.path.exists(device)
if not device_exists:
health_persistence.resolve_error(
err_key, 'Device no longer present in system')
continue

View File

@@ -1765,6 +1765,47 @@ class HealthPersistence:
except Exception as e:
print(f"[HealthPersistence] Error marking removed disks: {e}")
def cleanup_orphan_observations(self):
"""
Dismiss observations for devices that no longer exist in /dev/.
Useful for cleaning up after USB drives or temporary devices are disconnected.
"""
import os
import re
try:
conn = self._get_conn()
cursor = conn.cursor()
# Get all active (non-dismissed) observations
cursor.execute('''
SELECT id, device_name, serial FROM disk_observations
WHERE dismissed = 0
''')
observations = cursor.fetchall()
dismissed_count = 0
for obs_id, device_name, serial in observations:
# Check if device exists
dev_path = f'/dev/{device_name}'
# Also check base device (remove partition number)
base_dev = re.sub(r'\d+$', '', device_name)
base_path = f'/dev/{base_dev}'
if not os.path.exists(dev_path) and not os.path.exists(base_path):
cursor.execute('''
UPDATE disk_observations SET dismissed = 1
WHERE id = ?
''', (obs_id,))
dismissed_count += 1
conn.commit()
conn.close()
print(f"[HealthPersistence] Cleaned up {dismissed_count} orphan observations")
return dismissed_count
except Exception as e:
print(f"[HealthPersistence] Error cleaning orphan observations: {e}")
return 0
# Global instance
health_persistence = HealthPersistence()