slice 10A: activate the control envelope (Down channel) + hub-backed desired provider (v0.15.0)
The control envelope becomes live: the agent caches the hub's desired-state +
generation and re-fetches GET /hosts/{id}/desired-state only when the
generation advances. A new internal/desired Syncer maps the wire shape into a
reconcile.CachingProvider feeding the engine; benign deltas reconcile, an
explicit guest decommission is gated pending_signature (exec is 10B). Adds the
DesiredStateResponse/WireDesiredState wire types + Client.FetchDesiredState +
the loop EnvelopeObserver seam. Cross-repo golden (envelope + desired-state)
byte-identical with the hub.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,7 @@ import (
|
||||
"gitea.dooplex.hu/admin/felhom-agent/internal/authz"
|
||||
"gitea.dooplex.hu/admin/felhom-agent/internal/backup"
|
||||
"gitea.dooplex.hu/admin/felhom-agent/internal/config"
|
||||
"gitea.dooplex.hu/admin/felhom-agent/internal/desired"
|
||||
"gitea.dooplex.hu/admin/felhom-agent/internal/escrow"
|
||||
"gitea.dooplex.hu/admin/felhom-agent/internal/hub"
|
||||
"gitea.dooplex.hu/admin/felhom-agent/internal/localapi"
|
||||
@@ -40,7 +41,7 @@ import (
|
||||
|
||||
// version is the agent version. Overridable at build time with
|
||||
// -ldflags "-X main.version=<v>"; defaults to the in-repo CHANGELOG version.
|
||||
var version = "0.14.0"
|
||||
var version = "0.15.0"
|
||||
|
||||
func main() {
|
||||
var (
|
||||
@@ -237,6 +238,15 @@ func runDaemon(cfg config.Config, logger *slog.Logger) int {
|
||||
loop := hub.NewLoop(collector, client, time.Duration(hcfg.PollSeconds)*time.Second, logger)
|
||||
interval := time.Duration(hcfg.PollSeconds) * time.Second
|
||||
|
||||
// Desired-state provider (slice 10A): the hub-served target the reconcile engine converges
|
||||
// toward. Starts EMPTY (generation 0) — reconcile is a live no-op until the hub serves intent,
|
||||
// exactly like the slice-4 EmptyProvider. The desired.Syncer (wired below) fills it when the
|
||||
// control envelope's generation advances. Replaces EmptyProvider in the engine.
|
||||
desiredProvider := reconcile.NewCachingProvider()
|
||||
// The "Down" channel sync hook: on each heartbeat, fetch desired-state when the generation
|
||||
// advances. The loop calls it via the EnvelopeObserver seam (hub does not import desired).
|
||||
loop.SetEnvelopeObserver(desired.NewSyncer(client, desiredProvider, logger))
|
||||
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
logger.Info("felhom-agent daemon starting",
|
||||
@@ -304,7 +314,7 @@ func runDaemon(cfg config.Config, logger *slog.Logger) int {
|
||||
API: px,
|
||||
Queue: queue,
|
||||
Journal: journal,
|
||||
Provider: reconcile.EmptyProvider{}, // slice 4: no live desired-state source
|
||||
Provider: desiredProvider, // slice 10A: hub-served desired-state (empty until the hub serves intent)
|
||||
Gate: gate,
|
||||
HostID: cfg.Hub.HostID,
|
||||
Logger: logger,
|
||||
|
||||
Reference in New Issue
Block a user