122 lines
6.0 KiB
Python
122 lines
6.0 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import UTC, datetime, timedelta
|
|
from uuid import UUID, uuid5
|
|
|
|
from .models import (
|
|
ComponentRole,
|
|
Criticality,
|
|
DiscoveryCategory,
|
|
HealthStatus,
|
|
ProbeResult,
|
|
Service,
|
|
ServiceKind,
|
|
)
|
|
|
|
DEMO_SCENARIO_NAME = "Northstar Platform"
|
|
DEMO_ROOT_CAUSE_NAME = "PostgreSQL"
|
|
_DEMO_NAMESPACE = UUID("4b3f31f4-8ee8-4e34-9a30-4bd4e5d4d4c1")
|
|
|
|
|
|
def _stable_id(label: str) -> str:
|
|
return str(uuid5(_DEMO_NAMESPACE, label))
|
|
|
|
|
|
def build_demo_records(now: datetime | None = None) -> tuple[list[Service], list[ProbeResult]]:
|
|
"""Build the complete deterministic Northstar topology and its synthetic history."""
|
|
|
|
current = now or datetime.now(UTC)
|
|
definitions = [
|
|
("Public Endpoint", ServiceKind.HTTP, "https://northstar.synthetic/public", None, None, ["Reverse Proxy"]),
|
|
("Reverse Proxy", ServiceKind.HTTP, "https://northstar.synthetic/proxy", None, None, ["Web Frontend", "Auth Service"]),
|
|
("Web Frontend", ServiceKind.HTTP, "https://northstar.synthetic/web", None, None, ["API Gateway"]),
|
|
("Auth Service", ServiceKind.HTTP, "https://northstar.synthetic/auth", None, None, []),
|
|
("API Gateway", ServiceKind.HTTP, "https://northstar.synthetic/api", None, None, ["PostgreSQL", "Redis"]),
|
|
("PostgreSQL", ServiceKind.TCP, None, "postgresql.northstar.synthetic", 5432, []),
|
|
("Redis", ServiceKind.TCP, None, "redis.northstar.synthetic", 6379, []),
|
|
("Background Worker", ServiceKind.TCP, None, "worker.northstar.synthetic", 9000, ["PostgreSQL", "Redis", "Object Storage"]),
|
|
("Object Storage", ServiceKind.HTTP, "https://northstar.synthetic/object-storage", None, None, []),
|
|
]
|
|
ids_by_name = {name: _stable_id(f"service:{name}") for name, *_ in definitions}
|
|
metadata = {
|
|
"Public Endpoint": ("Edge", "Public Gateway", "Edge", ComponentRole.FRONTEND, DiscoveryCategory.PROXY, Criticality.CRITICAL, "Customer-facing availability check", 100.0),
|
|
"Reverse Proxy": ("Edge", "Public Gateway", "Edge", ComponentRole.PROXY, DiscoveryCategory.PROXY, Criticality.HIGH, "Northstar ingress gateway", 100.0),
|
|
"Web Frontend": ("Application", "Northstar App", "Application", ComponentRole.FRONTEND, DiscoveryCategory.APPLICATION, Criticality.HIGH, "Browser application", 99.0),
|
|
"Auth Service": ("Application", "Northstar App", "Application", ComponentRole.API, DiscoveryCategory.APPLICATION, Criticality.HIGH, "Identity and session service", 100.0),
|
|
"API Gateway": ("Application", "Northstar App", "Application", ComponentRole.API, DiscoveryCategory.APPLICATION, Criticality.CRITICAL, "Application API entry point", 99.0),
|
|
"PostgreSQL": ("Data", "Data Platform", "Data", ComponentRole.DATABASE, DiscoveryCategory.DATABASE, Criticality.CRITICAL, "Primary relational datastore", 99.9),
|
|
"Redis": ("Data", "Data Platform", "Data", ComponentRole.CACHE, DiscoveryCategory.CACHE, Criticality.HIGH, "Cache and queue backend", 100.0),
|
|
"Background Worker": ("Application", "Worker Platform", "Application", ComponentRole.WORKER, DiscoveryCategory.BACKGROUND_WORKER, Criticality.HIGH, "Asynchronous job processor", 99.0),
|
|
"Object Storage": ("Data", "Worker Platform", "Application", ComponentRole.STORAGE, DiscoveryCategory.STORAGE, Criticality.MEDIUM, "Durable object store", 100.0),
|
|
}
|
|
services = [
|
|
Service(
|
|
id=ids_by_name[name],
|
|
name=name,
|
|
kind=kind,
|
|
url=url,
|
|
host=host,
|
|
port=port,
|
|
depends_on=[ids_by_name[item] for item in dependencies],
|
|
group=metadata[name][0],
|
|
environment="production",
|
|
application=metadata[name][1],
|
|
domain=metadata[name][2],
|
|
component_role=metadata[name][3],
|
|
category=metadata[name][4],
|
|
criticality=metadata[name][5],
|
|
description=metadata[name][6],
|
|
availability_target=metadata[name][7],
|
|
interval_seconds=60,
|
|
created_at=current - timedelta(days=30),
|
|
updated_at=current,
|
|
)
|
|
for name, kind, url, host, port, dependencies in definitions
|
|
]
|
|
|
|
probes: list[ProbeResult] = []
|
|
for name, *_ in definitions:
|
|
for index in range(24):
|
|
status = _history_status(name, index)
|
|
checked_at = current - timedelta(hours=23 - index)
|
|
latency = None if status == HealthStatus.DOWN else round(42 + ((index * 17 + len(name) * 3) % 120), 2)
|
|
detail = _probe_detail(name, status, index)
|
|
probes.append(
|
|
ProbeResult(
|
|
id=_stable_id(f"probe:{name}:{index}"),
|
|
service_id=ids_by_name[name],
|
|
status=status,
|
|
latency_ms=latency,
|
|
detail=detail,
|
|
checked_at=checked_at,
|
|
trigger="synthetic",
|
|
metadata={"scenario": DEMO_SCENARIO_NAME},
|
|
)
|
|
)
|
|
return services, probes
|
|
|
|
|
|
def _history_status(name: str, index: int) -> HealthStatus:
|
|
if name == "PostgreSQL":
|
|
if index in {21, 23}:
|
|
return HealthStatus.DOWN
|
|
if index == 22:
|
|
return HealthStatus.DEGRADED
|
|
if name in {"API Gateway", "Background Worker"} and index == 20:
|
|
return HealthStatus.DOWN
|
|
if name == "Web Frontend" and index == 21:
|
|
return HealthStatus.DOWN
|
|
if name == "Reverse Proxy" and index == 22:
|
|
return HealthStatus.DEGRADED
|
|
return HealthStatus.HEALTHY
|
|
|
|
|
|
def _probe_detail(name: str, status: HealthStatus, index: int) -> str:
|
|
if name == DEMO_ROOT_CAUSE_NAME and status == HealthStatus.DOWN:
|
|
return "Synthetic outage: PostgreSQL connection refused"
|
|
if status == HealthStatus.DOWN:
|
|
return f"Synthetic dependency impact observed at history point {index + 1}"
|
|
if status == HealthStatus.DEGRADED:
|
|
return f"Synthetic elevated latency observed at history point {index + 1}"
|
|
return "Synthetic monitoring observation"
|