fix: remove legacy service dirs from setup_cell, update sanity_check for optional services
Unit Tests / test (push) Successful in 11m24s
Unit Tests / test (push) Successful in 11m24s
setup_cell.py no longer creates mail/radicale/webdav config and data dirs — those are managed by ServiceComposer when services are installed. Added data/services/ for ServiceComposer. sanity_check.py now uses stdlib urllib and discovers installed services via /api/services/active before checking their status routes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+53
-48
@@ -1,60 +1,65 @@
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
import json
|
||||
import sys
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
|
||||
# Updated endpoints to use HTTPS
|
||||
SERVICES = [
|
||||
{"name": "Dashboard UI", "url": "https://localhost/"},
|
||||
{"name": "Mail UI", "url": "https://localhost/mail"},
|
||||
{"name": "Calendar UI", "url": "https://localhost/calendar"},
|
||||
{"name": "Files UI", "url": "https://localhost/files"},
|
||||
{"name": "DNS Management UI", "url": "https://localhost/dns"},
|
||||
{"name": "API Health", "url": "https://localhost/api/health", "is_api": True},
|
||||
{"name": "API Service Status", "url": "https://localhost/api/services/status", "is_api": True},
|
||||
BASE = "http://127.0.0.1:3000"
|
||||
|
||||
CORE_CHECKS = [
|
||||
{"name": "API health", "path": "/health"},
|
||||
{"name": "API status", "path": "/api/status"},
|
||||
{"name": "Active services", "path": "/api/services/active"},
|
||||
]
|
||||
|
||||
def check_ui(url, name):
|
||||
try:
|
||||
resp = requests.get(url, timeout=5, verify=False)
|
||||
if resp.status_code == 200:
|
||||
# Try to parse HTML and look for a title or main element
|
||||
soup = BeautifulSoup(resp.text, "html.parser")
|
||||
title = soup.title.string if soup.title else "No title"
|
||||
print(f"[OK] {name} ({url}) - {title}")
|
||||
return True
|
||||
else:
|
||||
print(f"[FAIL] {name} ({url}) - HTTP {resp.status_code}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"[ERROR] {name} ({url}) - {e}")
|
||||
return False
|
||||
OPTIONAL_SERVICE_CHECKS = {
|
||||
"email": {"name": "Email status", "path": "/api/email/status"},
|
||||
"calendar": {"name": "Calendar status", "path": "/api/calendar/status"},
|
||||
"files": {"name": "Files status", "path": "/api/files/status"},
|
||||
}
|
||||
|
||||
def check_api_status(url, name):
|
||||
|
||||
def get(path):
|
||||
try:
|
||||
resp = requests.get(url, timeout=5, verify=False)
|
||||
if resp.status_code == 200:
|
||||
print(f"[OK] {name}: {url}")
|
||||
if 'services/status' in url:
|
||||
data = resp.json()
|
||||
for service, status in data.items():
|
||||
s = status.get("status", "Unknown")
|
||||
print(f" {service}: {s}")
|
||||
else:
|
||||
print(f" Response: {resp.text.strip()}")
|
||||
return True
|
||||
else:
|
||||
print(f"[FAIL] {name}: HTTP {resp.status_code}")
|
||||
return False
|
||||
resp = urllib.request.urlopen(BASE + path, timeout=5)
|
||||
body = resp.read().decode()
|
||||
return resp.status, body
|
||||
except urllib.error.HTTPError as e:
|
||||
return e.code, e.read().decode()
|
||||
except Exception as e:
|
||||
print(f"[ERROR] {name}: {e}")
|
||||
return False
|
||||
return None, str(e)
|
||||
|
||||
|
||||
def main():
|
||||
print("=== UI & API Sanity Checks (Caddy-proxied, HTTPS) ===")
|
||||
for svc in SERVICES:
|
||||
if svc.get("is_api"):
|
||||
check_api_status(svc["url"], svc["name"])
|
||||
print("=== PIC Sanity Check ===")
|
||||
|
||||
for chk in CORE_CHECKS:
|
||||
code, body = get(chk["path"])
|
||||
if code == 200:
|
||||
print(f"[OK] {chk['name']}")
|
||||
else:
|
||||
check_ui(svc["url"], svc["name"])
|
||||
print(f"[FAIL] {chk['name']} — HTTP {code}: {body[:120]}")
|
||||
|
||||
# Discover installed services and check only those
|
||||
code, body = get("/api/services/active")
|
||||
installed_ids = set()
|
||||
if code == 200:
|
||||
try:
|
||||
installed_ids = {svc["id"] for svc in json.loads(body)}
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
print()
|
||||
print("Optional services:")
|
||||
for svc_id, chk in OPTIONAL_SERVICE_CHECKS.items():
|
||||
if svc_id not in installed_ids:
|
||||
print(f"[SKIP] {chk['name']} — not installed")
|
||||
continue
|
||||
code, body = get(chk["path"])
|
||||
if code == 200:
|
||||
print(f"[OK] {chk['name']}")
|
||||
else:
|
||||
print(f"[FAIL] {chk['name']} — HTTP {code}: {body[:120]}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+1
-11
@@ -19,26 +19,18 @@ REQUIRED_DIRS = [
|
||||
'config/dns',
|
||||
'config/dhcp',
|
||||
'config/ntp',
|
||||
'config/mail/config',
|
||||
'config/mail/ssl',
|
||||
'config/radicale',
|
||||
'config/webdav',
|
||||
'config/wireguard',
|
||||
'config/api',
|
||||
'data/caddy',
|
||||
'data/dns',
|
||||
'data/dhcp',
|
||||
'data/maildata',
|
||||
'data/mailstate',
|
||||
'data/maillogs',
|
||||
'data/radicale',
|
||||
'data/files',
|
||||
'data/api',
|
||||
'data/vault/certs',
|
||||
'data/vault/keys',
|
||||
'data/vault/trust',
|
||||
'data/vault/ca',
|
||||
'data/logs',
|
||||
'data/services',
|
||||
'data/wireguard/keys/peers',
|
||||
'data/wireguard/wg_confs',
|
||||
]
|
||||
@@ -47,8 +39,6 @@ REQUIRED_FILES = [
|
||||
'config/dns/Corefile',
|
||||
'config/dhcp/dnsmasq.conf',
|
||||
'config/ntp/chrony.conf',
|
||||
'config/mail/mailserver.env',
|
||||
'config/webdav/users.passwd',
|
||||
]
|
||||
|
||||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
Reference in New Issue
Block a user