feat(agent/collector): topology-label discovery and master-authoritative supersede
Legacy fleet deckies live in decnet-state.json; MazeNET topology containers don't. Tag them at compose-time with decnet.topology.service=true and let the collector match on that label. Spin up the agent's log collector on the first successful /topology/apply (not in the lifespan — that would break the no-docker-on-boot invariant) and tear it down with the app. Land log lines in DECNET_AGENT_LOG_FILE, separate from master-side DECNET_INGEST_LOG_FILE, so a dev box running both roles can't forward its own ingest back to itself. When master pushes a topology that differs from whatever is pinned locally, teardown the predecessor and accept the new one. Refusing with 409 left the agent stranded after partial deploys. record_error now persists the hydrated blob so a later teardown can still walk the LAN list — otherwise a half-failed apply strands containers + bridges with no breadcrumb back to them.
This commit is contained in:
@@ -130,7 +130,12 @@ class TopologyStore:
|
||||
)
|
||||
self._conn.commit()
|
||||
|
||||
def record_error(self, topology_id: str, message: str) -> None:
|
||||
def record_error(
|
||||
self,
|
||||
topology_id: str,
|
||||
message: str,
|
||||
hydrated: Optional[dict[str, Any]] = None,
|
||||
) -> None:
|
||||
"""Attach a last-error message for *topology_id*.
|
||||
|
||||
Upserts a marker row when no apply has yet succeeded for this
|
||||
@@ -139,14 +144,24 @@ class TopologyStore:
|
||||
/topology/state and the next heartbeat. The marker row uses an
|
||||
empty ``applied_version_hash`` so master's heartbeat check sees
|
||||
the hash mismatch and schedules a resync.
|
||||
|
||||
If *hydrated* is provided it is stored so a later teardown can
|
||||
still walk the LAN list — otherwise a partial deploy is strands
|
||||
containers + bridges with no breadcrumb back to them.
|
||||
"""
|
||||
blob = json.dumps(hydrated, sort_keys=True) if hydrated else "{}"
|
||||
self._conn.execute(
|
||||
"INSERT INTO applied_topology"
|
||||
" (topology_id, applied_version_hash, hydrated_blob_json,"
|
||||
" applied_at, last_error)"
|
||||
" VALUES (?, '', '{}', 0, ?)"
|
||||
" ON CONFLICT(topology_id) DO UPDATE SET last_error=excluded.last_error",
|
||||
(topology_id, message),
|
||||
" VALUES (?, '', ?, 0, ?)"
|
||||
" ON CONFLICT(topology_id) DO UPDATE SET"
|
||||
" last_error=excluded.last_error,"
|
||||
" hydrated_blob_json=CASE"
|
||||
" WHEN applied_topology.hydrated_blob_json='{}'"
|
||||
" THEN excluded.hydrated_blob_json"
|
||||
" ELSE applied_topology.hydrated_blob_json END",
|
||||
(topology_id, blob, message),
|
||||
)
|
||||
self._conn.commit()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user