apps/dashboard/backend/app/services/aggregator.py aktualisiert
This commit is contained in:
@@ -120,7 +120,7 @@ class AggregatorService:
|
|||||||
async def get_immich(self) -> ImmichSnapshot:
|
async def get_immich(self) -> ImmichSnapshot:
|
||||||
return await self.cache.get_or_load(
|
return await self.cache.get_or_load(
|
||||||
"immich",
|
"immich",
|
||||||
self.settings.cache_ttl_storage_seconds,
|
self.settings.cache_ttl_services_seconds,
|
||||||
self.immich_client.fetch_stats,
|
self.immich_client.fetch_stats,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -191,19 +191,42 @@ class AggregatorService:
|
|||||||
async def _build_storage(self) -> StorageResponse:
|
async def _build_storage(self) -> StorageResponse:
|
||||||
snapshot = await self.beszel_client.fetch_system_snapshot()
|
snapshot = await self.beszel_client.fetch_system_snapshot()
|
||||||
now = datetime.now(timezone.utc)
|
now = datetime.now(timezone.utc)
|
||||||
|
|
||||||
disks = [self._map_disk(d, snapshot.source_status) for d in snapshot.disks]
|
disks = [self._map_disk(d, snapshot.source_status) for d in snapshot.disks]
|
||||||
total_used = sum(d.used_gb for d in snapshot.disks)
|
storage_source_status = snapshot.source_status
|
||||||
total_size = sum(d.total_gb for d in snapshot.disks)
|
if snapshot.source_status == "online" and not disks:
|
||||||
total_free = sum(d.free_gb for d in snapshot.disks)
|
storage_source_status = "unsupported"
|
||||||
overall_pct = round(total_used / total_size * 100, 1) if total_size > 0 else 0.0
|
|
||||||
|
if disks:
|
||||||
|
root = next((d for d in disks if d.mount == "/"), disks[0])
|
||||||
|
else:
|
||||||
|
root = StorageDisk(
|
||||||
|
name="rootfs",
|
||||||
|
mount="/",
|
||||||
|
used_gb=0.0,
|
||||||
|
total_gb=0.0,
|
||||||
|
free_gb=0.0,
|
||||||
|
usage_percent=0.0,
|
||||||
|
status="offline" if snapshot.source_status == "offline" else "online",
|
||||||
|
)
|
||||||
|
|
||||||
|
critical_count = sum(1 for d in disks if d.status == "critical")
|
||||||
|
warning_count = sum(1 for d in disks if d.status == "warning")
|
||||||
|
overall_status: OverallStatus = (
|
||||||
|
"offline" if snapshot.source_status == "offline"
|
||||||
|
else ("degraded" if critical_count or warning_count else "online")
|
||||||
|
)
|
||||||
|
|
||||||
return StorageResponse(
|
return StorageResponse(
|
||||||
generated_at=now,
|
generated_at=now,
|
||||||
summary=StorageSummary(
|
summary=StorageSummary(
|
||||||
total_used_gb=round(total_used, 2),
|
overall_status=overall_status,
|
||||||
total_size_gb=round(total_size, 2),
|
source_status=storage_source_status,
|
||||||
total_free_gb=round(total_free, 2),
|
critical_disks=critical_count,
|
||||||
overall_usage_percent=overall_pct,
|
warning_disks=warning_count,
|
||||||
|
total_disks=len(disks),
|
||||||
),
|
),
|
||||||
|
root=root,
|
||||||
disks=disks,
|
disks=disks,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -214,46 +237,57 @@ class AggregatorService:
|
|||||||
)
|
)
|
||||||
now = datetime.now(timezone.utc)
|
now = datetime.now(timezone.utc)
|
||||||
|
|
||||||
monitor_by_name = {m.name.lower(): m for m in uk_snap.monitors}
|
monitor_by_name = {
|
||||||
|
self._normalize_identifier(m.name): m for m in uk_snap.monitors
|
||||||
|
}
|
||||||
|
docker_by_name = {
|
||||||
|
self._normalize_identifier(c.name): c for c in docker_snap.containers
|
||||||
|
}
|
||||||
|
|
||||||
items: list[ServiceItem] = []
|
items: list[ServiceItem] = []
|
||||||
for container in docker_snap.containers:
|
merged_names = sorted(set(docker_by_name) | set(monitor_by_name))
|
||||||
name_lower = container.name.lower()
|
for norm in merged_names:
|
||||||
monitor = monitor_by_name.get(name_lower)
|
container = docker_by_name.get(norm)
|
||||||
overall = self._resolve_overall_status(container.state, monitor)
|
monitor = monitor_by_name.get(norm)
|
||||||
|
status = self._resolve_overall_status(
|
||||||
|
container.state if container else "unknown", monitor
|
||||||
|
)
|
||||||
items.append(ServiceItem(
|
items.append(ServiceItem(
|
||||||
name=container.name,
|
id=norm,
|
||||||
docker_state=container.state,
|
name=monitor.name if monitor else container.name,
|
||||||
uptime_kuma_status=monitor.status if monitor else None,
|
kind="service",
|
||||||
overall_status=overall,
|
status=status,
|
||||||
health=self._status_to_health(overall),
|
health=self._status_to_health(status),
|
||||||
|
latency_ms=monitor.latency_ms if monitor else None,
|
||||||
|
docker_state=container.state if container else "unknown",
|
||||||
|
url=None,
|
||||||
|
source="uptime_kuma" if monitor else "docker",
|
||||||
|
last_checked=now.isoformat(),
|
||||||
))
|
))
|
||||||
|
|
||||||
statuses: list[OverallStatus] = [i.overall_status for i in items]
|
statuses = [i.status for i in items]
|
||||||
summary_status = self._aggregate_statuses(statuses)
|
overall = self._aggregate_statuses(statuses)
|
||||||
|
|
||||||
return ServicesResponse(
|
return ServicesResponse(
|
||||||
generated_at=now,
|
generated_at=now,
|
||||||
summary=ServicesSummary(
|
summary=ServicesSummary(
|
||||||
overall_status=summary_status,
|
overall_status=overall,
|
||||||
total=len(items),
|
docker=ServicesDockerSummary(
|
||||||
online=sum(1 for s in statuses if s == "online"),
|
running=docker_snap.running,
|
||||||
degraded=sum(1 for s in statuses if s == "degraded"),
|
stopped=docker_snap.stopped,
|
||||||
offline=sum(1 for s in statuses if s == "offline"),
|
unhealthy=docker_snap.unhealthy,
|
||||||
|
total=docker_snap.total,
|
||||||
|
source_status=docker_snap.source_status,
|
||||||
|
),
|
||||||
|
uptime_kuma=ServicesUptimeKumaSummary(
|
||||||
|
monitors_up=uk_snap.monitors_up,
|
||||||
|
monitors_down=uk_snap.monitors_down,
|
||||||
|
monitors_paused=uk_snap.monitors_paused,
|
||||||
|
total=uk_snap.total,
|
||||||
|
source_status=uk_snap.source_status,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
docker=ServicesDockerSummary(
|
services=items,
|
||||||
running=docker_snap.running,
|
|
||||||
stopped=docker_snap.stopped,
|
|
||||||
unhealthy=docker_snap.unhealthy,
|
|
||||||
total=docker_snap.total,
|
|
||||||
source_status=docker_snap.source_status,
|
|
||||||
),
|
|
||||||
uptime_kuma=ServicesUptimeKumaSummary(
|
|
||||||
monitors_up=uk_snap.monitors_up,
|
|
||||||
monitors_down=uk_snap.monitors_down,
|
|
||||||
source_status=uk_snap.source_status,
|
|
||||||
),
|
|
||||||
items=items,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
async def _build_overview(self) -> OverviewResponse:
|
async def _build_overview(self) -> OverviewResponse:
|
||||||
@@ -267,8 +301,11 @@ class AggregatorService:
|
|||||||
|
|
||||||
statuses: list[OverallStatus] = []
|
statuses: list[OverallStatus] = []
|
||||||
for container in docker_snap.containers:
|
for container in docker_snap.containers:
|
||||||
name_lower = container.name.lower()
|
name_lower = self._normalize_identifier(container.name)
|
||||||
monitor = next((m for m in uk_snap.monitors if m.name.lower() == name_lower), None)
|
monitor = next(
|
||||||
|
(m for m in uk_snap.monitors if self._normalize_identifier(m.name) == name_lower),
|
||||||
|
None,
|
||||||
|
)
|
||||||
statuses.append(self._resolve_overall_status(container.state, monitor))
|
statuses.append(self._resolve_overall_status(container.state, monitor))
|
||||||
|
|
||||||
overall = self._aggregate_statuses(statuses)
|
overall = self._aggregate_statuses(statuses)
|
||||||
@@ -293,7 +330,7 @@ class AggregatorService:
|
|||||||
system=OverviewSystemSummary(
|
system=OverviewSystemSummary(
|
||||||
cpu_percent=system_snap.cpu_usage_percent,
|
cpu_percent=system_snap.cpu_usage_percent,
|
||||||
ram_percent=system_snap.memory_usage_percent,
|
ram_percent=system_snap.memory_usage_percent,
|
||||||
root_storage_percent=system_snap.disks[0].usage_percent if system_snap.disks else 0,
|
root_storage_percent=system_snap.disks[0].usage_percent if system_snap.disks else 0.0,
|
||||||
network_rx_mbps=system_snap.network_rx_mbps,
|
network_rx_mbps=system_snap.network_rx_mbps,
|
||||||
network_tx_mbps=system_snap.network_tx_mbps,
|
network_tx_mbps=system_snap.network_tx_mbps,
|
||||||
uptime_seconds=system_snap.uptime_seconds,
|
uptime_seconds=system_snap.uptime_seconds,
|
||||||
@@ -303,10 +340,14 @@ class AggregatorService:
|
|||||||
label=ha_snap.label,
|
label=ha_snap.label,
|
||||||
version=ha_snap.version,
|
version=ha_snap.version,
|
||||||
response_time_ms=ha_snap.response_time_ms,
|
response_time_ms=ha_snap.response_time_ms,
|
||||||
last_checked=ha_snap.last_checked,
|
last_checked=ha_snap.last_checked.isoformat() if ha_snap.last_checked else None,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _normalize_identifier(value: str) -> str:
|
||||||
|
return "".join(ch.lower() for ch in value if ch.isalnum())
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _resolve_overall_status(
|
def _resolve_overall_status(
|
||||||
docker_state: str,
|
docker_state: str,
|
||||||
@@ -317,7 +358,6 @@ class AggregatorService:
|
|||||||
return "offline"
|
return "offline"
|
||||||
if monitor.status == "degraded":
|
if monitor.status == "degraded":
|
||||||
return "degraded"
|
return "degraded"
|
||||||
|
|
||||||
if docker_state == "unhealthy":
|
if docker_state == "unhealthy":
|
||||||
return "degraded"
|
return "degraded"
|
||||||
if docker_state == "stopped":
|
if docker_state == "stopped":
|
||||||
@@ -342,7 +382,8 @@ class AggregatorService:
|
|||||||
elif disk.usage_percent >= 75:
|
elif disk.usage_percent >= 75:
|
||||||
status = "warning"
|
status = "warning"
|
||||||
else:
|
else:
|
||||||
status = "healthy"
|
status = "online"
|
||||||
|
|
||||||
return StorageDisk(
|
return StorageDisk(
|
||||||
name=disk.name,
|
name=disk.name,
|
||||||
mount=disk.mount,
|
mount=disk.mount,
|
||||||
@@ -358,9 +399,9 @@ class AggregatorService:
|
|||||||
normalized = list(statuses)
|
normalized = list(statuses)
|
||||||
if not normalized:
|
if not normalized:
|
||||||
return "offline"
|
return "offline"
|
||||||
if any(status == "offline" for status in normalized):
|
if any(s == "offline" for s in normalized):
|
||||||
return "degraded" if any(status == "online" for status in normalized) else "offline"
|
return "degraded" if any(s == "online" for s in normalized) else "offline"
|
||||||
if any(status in {"degraded", "warning", "critical"} for status in normalized):
|
if any(s in {"degraded", "warning", "critical"} for s in normalized):
|
||||||
return "degraded"
|
return "degraded"
|
||||||
return "online"
|
return "online"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user