homelab-codex-ws/inventory/topology.yaml
oskar aa8276963c feat(topology): node status active|dormant + dormant handling in control plane
topology.yaml (per its own rule that hosts/*/services.yaml are
authoritative, recon F20.1):
- add status field; chelsty-infra + chelsty-ha -> dormant (site hardware
  down since ~2026-06-01, revival planned)
- add lustro as a full active node (runs node-agent, ships events, F20.11)
- drop per-node service lists (vps list contradicted hosts/vps, F20.1;
  piha/solaria lists were stale too, F20.8/F20.9) — node-level truth only
- deployment.mode pull -> push: every deploy script SSH-pushes from
  saturn (F20.10)

Dormant semantics in code:
- observer (scripts/observer/observer.py): loads status from topology;
  _prune_stale_world skips dormant nodes — last-known world state stays
  frozen, no node_offline/node_stale/node_online events emitted
- supervisor (services/control-plane/src/supervisor.py): reloads dormant
  set each reconcile; dormant hosts' services excluded from desired state
  (existing pending actions auto-cancel via
  service_removed_from_desired_state), disk_cleanup skipped, node/HA
  events from dormant nodes not routed to alerts

Tests: services/control-plane/tests/test_dormant_nodes.py (9 cases);
full suite 145 passed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 19:15:55 +02:00

115 lines
3.2 KiB
YAML

topology:
mesh: tailscale
git_provider: forgejo
deployment:
# Every deploy script SSH-pushes from saturn to the target node (recon
# F20.10); "pull" never matched reality.
mode: push
orchestrator: saturn
# Ingress dla usług domowych przez NPM @ PIHA + wildcard cert kapala.org.
# Od 2026-06-30. Poprzednia ścieżka (add-on Tailscale na ha-ken) PORZUCONA.
# DNS kapala.org: Cloudflare, wildcard *.kapala.org via DNS-01 (auto-renew).
# Mail: Fastmail (MX/DKIM/SPF na CF, DNS only).
# Subdomeny mesh: A → 100.108.208.3 (Tailscale PIHA), DNS only.
ingress:
dns_provider: cloudflare # kapala.org od 2026-06-30
wildcard_cert:
domain: "*.kapala.org"
method: dns-01 # Cloudflare DNS-01, auto-renew
proxy: npm-piha # Nginx Proxy Manager @ PIHA
services:
home_assistant:
host: 192.168.31.7
port: 8123
ingress: ha.kapala.org # NPM @ PIHA, cert *.kapala.org, mesh-only
access: tailscale # 100.108.208.3
cert: wildcard-kapala # DNS-01 Cloudflare, auto-renew
immich:
host: 192.168.31.5
port: 2283
ingress: immich.kapala.org # NPM @ PIHA, cert *.kapala.org, mesh-only
access: tailscale
cert: wildcard-kapala
# Node-level truth ONLY. Per-node service lists live in hosts/<node>/services.yaml
# (authoritative — the lists formerly duplicated here contradicted them, recon F20.1).
#
# status:
# active — node is monitored and remediated normally.
# dormant — node exists but is expected offline: the observer keeps its
# last-known world state and emits NO liveness events for it; the
# supervisor generates NO actions for it. See ARCHITEKTURA.md.
nodes:
saturn:
status: active
roles:
- control
- development
piha:
status: active
roles:
- infra
- monitoring
solaria:
# Powered off ~16 h/day BY DESIGN (on-demand compute desktop): one daily
# offline/online liveness cycle is expected, not a fault. Nothing that
# must run 24/7 may live here.
status: active
roles:
- compute
- ai
vps:
status: active
roles:
- edge
- ingress
- control-plane
lustro:
# MagicMirror Raspberry Pi — full monitored node: runs node-agent and
# ships events to the control plane (recon F20.11).
status: active
roles:
- edge
- display
chelsty-infra:
status: dormant
dormant_reason: "site hardware down since ~2026-06-01; will be revived later"
dormant_since: "2026-06-01"
site: chelsty
roles:
- remote
- hypervisor
- infra
- staging
connectivity:
uplink: lte
intermittent: true
home_automation:
offline_operation_required: true
coordinator:
model: SLZB-06U
connection: network
usb: false
chelsty-ha:
status: dormant
dormant_reason: "site hardware down since ~2026-06-01; will be revived later"
dormant_since: "2026-06-01"
site: chelsty
roles:
- remote
- homeassistant
connectivity:
uplink: lte
intermittent: true
home_automation:
offline_operation_required: true