Architecture Overview¶
Reconcile loop¶
The agent is built around a single reconcile loop that runs on a fixed interval (default: 30s).
┌───────────────────────────────────────────────────────────┐
│ Reconcile Engine │
│ │
│ 1. Load local state from bbolt │
│ 2. FetchDesiredState from backend │
│ 3. For each registered handler: │
│ handler.Reconcile(localState, desiredState) │
│ 4. Save updated state to bbolt │
│ 5. Report health via Heartbeat │
├───────────────────────────────────────────────────────────┤
│ Handler Registry │
│ ┌─────────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ PrivateNetwork │ │ Kubernetes │ │ Firewall │ │
│ │ Handler │ │ Handler │ │ Handler │ │
│ └─────────────────┘ └──────────────┘ └──────────────┘ │
├───────────────────────────────────────────────────────────┤
│ API Client │
│ FetchDesiredState() — pull desired state │
│ ReportResourceState() — push resource-specific data │
│ Heartbeat() — push health status │
└───────────────────────────────────────────────────────────┘
The agent never initiates actions — it only reacts to desired state changes from the platform.
Key design principles¶
- Declarative — the backend tells the agent what should exist, not how to do it
- Idempotent — every operation can be safely retried
- Extensible — new resource types are added by implementing a handler interface
- Crash-safe — state is persisted to bbolt; the agent can restart at any point
Resource handlers¶
Each resource type (private network, Kubernetes, firewall, etc.) has its own handler that implements:
type ResourceHandler interface {
Name() string
Reconcile(ctx context.Context, state *AgentState, desired *DesiredState) error
}
Handlers are responsible for:
- Detecting diffs between desired and current state
- Applying changes (create, update, delete)
- Reporting status back to the platform via
ReportResourceState - Storing handler-specific local state (e.g., WireGuard private keys)
State management¶
| State | Storage | Purpose |
|---|---|---|
| Desired state | Fetched from backend each cycle | What resources should exist |
| Local state | bbolt on disk (/var/lib/segla) |
Agent ID, resource keys, last applied state |
| Resource state | Reported to backend | Status of each resource (active, failed, etc.) |
Error handling¶
All operations are idempotent. Failures are logged and retried on the next cycle:
| Scenario | Behavior |
|---|---|
| FetchDesiredState fails | Skip cycle, retry next tick |
| Handler fails | Log error, continue other handlers |
| ReportResourceState fails | Retry next cycle |
| State save fails | Keys may regenerate (idempotent) |