fix: health history all-down — connectivity checks and UI data path
Service manager fixes (connectivity tests): - email_manager: replace telnet with socket.create_connection for SMTP/IMAP; replace nslookup with socket.getaddrinfo for DNS; exclude unconfigured domain from success (email healthy=False now correctly means ports refused, not missing domain) - calendar_manager: replace localhost:5232 with cell-radicale:5232; fix database check to test dir writability instead of file existence (files created on demand) - file_manager: replace localhost:8080 with cell-webdav:80; add top-level success key - network_manager: replace nslookup with socket.getaddrinfo; add success key to dhcp_test and ntp_test return values - routing_manager: exclude iptables_access from success (iptables runs in cell-wireguard, not API container) - wireguard_manager: add success key to no-arg test_connectivity result Health history UI: - SvcCol reads data?.status?.running || data?.status?.status — handles nested health check shape Result: network/wireguard/calendar/files/routing/vault all healthy=True. Email healthy=False is correct — mail server needs ≥1 account before Dovecot starts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+20
-42
@@ -111,60 +111,38 @@ class CalendarManager(BaseServiceManager):
|
||||
return False
|
||||
|
||||
def _test_service_connectivity(self) -> Dict[str, Any]:
|
||||
"""Test calendar service connectivity"""
|
||||
"""Test calendar service connectivity via TCP socket to cell-radicale container."""
|
||||
import socket
|
||||
try:
|
||||
# Test connection to calendar service
|
||||
result = subprocess.run(['curl', '-s', 'http://localhost:5232'],
|
||||
capture_output=True, text=True, timeout=5)
|
||||
|
||||
success = result.returncode == 0 and result.stdout.strip()
|
||||
return {
|
||||
'success': success,
|
||||
'message': 'Calendar service accessible' if success else 'Calendar service not accessible'
|
||||
}
|
||||
with socket.create_connection(('cell-radicale', 5232), timeout=5):
|
||||
pass
|
||||
return {'success': True, 'message': 'Calendar service accessible'}
|
||||
except Exception as e:
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Service test error: {str(e)}'
|
||||
}
|
||||
return {'success': False, 'message': f'Calendar service not accessible: {str(e)}'}
|
||||
|
||||
def _test_database_connectivity(self) -> Dict[str, Any]:
|
||||
"""Test database connectivity"""
|
||||
"""Test database connectivity — data dir must be writable; files are created on first use."""
|
||||
try:
|
||||
# Check if data files are accessible
|
||||
files_exist = all([
|
||||
os.path.exists(self.users_file),
|
||||
os.path.exists(self.calendars_file),
|
||||
os.path.exists(self.events_file)
|
||||
])
|
||||
|
||||
data_dir = os.path.dirname(self.users_file)
|
||||
os.makedirs(data_dir, exist_ok=True)
|
||||
accessible = os.access(data_dir, os.R_OK | os.W_OK)
|
||||
return {
|
||||
'success': files_exist,
|
||||
'message': 'Database files accessible' if files_exist else 'Database files not accessible'
|
||||
'success': accessible,
|
||||
'message': 'Database directory accessible' if accessible else 'Database directory not accessible'
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Database test error: {str(e)}'
|
||||
}
|
||||
return {'success': False, 'message': f'Database test error: {str(e)}'}
|
||||
|
||||
def _test_web_interface(self) -> Dict[str, Any]:
|
||||
"""Test web interface connectivity"""
|
||||
"""Test Radicale web interface via HTTP to cell-radicale container."""
|
||||
try:
|
||||
# Test web interface connection
|
||||
result = subprocess.run(['curl', '-s', 'http://localhost:5232'],
|
||||
capture_output=True, text=True, timeout=5)
|
||||
|
||||
success = result.returncode == 0 and 'radicale' in result.stdout.lower()
|
||||
return {
|
||||
'success': success,
|
||||
'message': 'Web interface accessible' if success else 'Web interface not accessible'
|
||||
}
|
||||
import urllib.request
|
||||
with urllib.request.urlopen('http://cell-radicale:5232', timeout=5) as r:
|
||||
body = r.read(512).decode('utf-8', errors='ignore').lower()
|
||||
success = r.status < 500
|
||||
return {'success': success, 'message': 'Web interface accessible' if success else 'Web interface not accessible'}
|
||||
except Exception as e:
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Web interface test error: {str(e)}'
|
||||
}
|
||||
return {'success': False, 'message': f'Web interface not accessible: {str(e)}'}
|
||||
|
||||
def _load_users(self) -> List[Dict[str, Any]]:
|
||||
"""Load calendar users from file"""
|
||||
|
||||
Reference in New Issue
Block a user