hub v0.59.0: Direction-2a agent-plane immediate-sync poke sender + ep0 felhom-poke surface

- internal/poke: pinned-host-key SSH poke sender (wgsync sibling) + fire-and-forget Notifier (PokeHost/PokeAllHosts). Poke refuses non-WG targets pre-dial; contentless via ep0 forced command to the box WG /32:51822.
- wiring: Server.SetPoke; applyPBSDR pokes the host after each descriptor gen-bump; handleSetArtifacts (MinAgent floor) pokes all hosts. main.go env POKE_SSH_KEY_FILE (reuses peersync endpoint/hostkey).
- scripts/felhom-poke.sh (non-root forced command) + offsite-endpoint.md §11; manifests/hub.yaml Secret/agent-poke + POKE_SSH_KEY_FILE (image tag bump follows the build).
This commit is contained in:
2026-07-16 22:48:15 +02:00
parent bdb65a80e8
commit eb227486d0
11 changed files with 567 additions and 0 deletions
+10
View File
@@ -25,6 +25,7 @@ import (
"strings"
"time"
"gitea.dooplex.hu/admin/felhom-hub/internal/poke"
"gitea.dooplex.hu/admin/felhom-hub/internal/store"
"gitea.dooplex.hu/admin/felhom-hub/internal/tenantsync"
)
@@ -39,6 +40,11 @@ type tenancyProvisioner interface {
// tier enabled returns an error (not configured on this hub); the form section still renders.
func (s *Server) SetTenantSync(p tenancyProvisioner) { s.tenantsync = p }
// SetPoke wires the agent-plane immediate-sync sender (v0.59.0, Direction-2a). Without it, an
// agent-plane desired-state save just bumps the generation and the box picks it up on its next
// ≤15-min report — the poke only shortens that to seconds. Optional.
func (s *Server) SetPoke(p *poke.Notifier) { s.poke = p }
// pbsDRDescriptor is the NON-SECRET pbs_dr block in a host's desired_json. It NEVER carries the
// token secret (that is host_pbs_secrets custody, consume-once).
type pbsDRDescriptor struct {
@@ -136,6 +142,7 @@ func (s *Server) applyPBSDR(ctx context.Context, r *http.Request, cfg *store.Cus
return fmt.Errorf("pbsdr: desired-state write: %w", err)
}
s.logger.Printf("[INFO] pbsdr disabled for %s (host %s, gen %d; ep0 tenancy kept)", cfg.CustomerID, host.HostID, gen)
s.poke.PokeHost(host.HostID) // agent-plane immediate-sync (Direction-2a): land the change in seconds
return nil
}
@@ -160,6 +167,7 @@ func (s *Server) applyPBSDR(ctx context.Context, r *http.Request, cfg *store.Cus
return fmt.Errorf("pbsdr: desired-state write: %w", err)
}
s.logger.Printf("[INFO] pbsdr descriptor updated for %s (host %s, gen %d; tenancy unchanged)", cfg.CustomerID, host.HostID, gen)
s.poke.PokeHost(host.HostID) // agent-plane immediate-sync (Direction-2a): land the change in seconds
return nil
}
@@ -171,6 +179,8 @@ func (s *Server) applyPBSDR(ctx context.Context, r *http.Request, cfg *store.Cus
}
if blocked != "" {
s.logger.Printf("[INFO] pbsdr: DR tier ON for %s — waiting: %s", cfg.CustomerID, blocked)
} else {
s.poke.PokeHost(host.HostID) // freshly provisioned + generation bumped → nudge the box now
}
return nil
}