Documentation
¶
Overview ¶
Package deployer applies a validated render to the HAProxy fleet through the HAPTIC agent that owns each pod's file tree.
The Deployer is a stateless executor: it receives DeploymentScheduledEvent and, per pod, reads the agent's baseline, diffs the render against it (pkg/dataplane/deployplan) and sends the resulting fenced applies. All scheduling, rate limiting and queueing lives in the DeploymentScheduler.
Package deployer implements deployment scheduling and execution components.
Index ¶
- Constants
- type AckedPlanSink
- type Component
- func (c *Component) CoalescesOn() []string
- func (c *Component) Drain(ctx context.Context) error
- func (c *Component) HandleEvent(event busevents.Event)
- func (c *Component) HealthCheck() error
- func (c *Component) SetValidatedOccurrence(occurrence *rendercycle.Occurrence)
- func (c *Component) Start(ctx context.Context) error
- type DeployStack
- type DeploymentScheduler
- type DriftPreventionMonitor
- type FleetCapabilitiesSink
- type LeadershipFence
- type RenderInputs
- type RetainedChecker
- type RetainedIntentStore
- type RetainedLoader
- type RetainedStore
Constants ¶
const ( // ComponentName is the unique identifier for this component. ComponentName = "deployer" // EventBufferSize is the size of the event subscription buffer. // Low-volume component (~1-2 deployment events per reconciliation cycle). EventBufferSize = busevents.StandardSubscriberBuffer )
const ( // SchedulerComponentName is the unique identifier for the DeploymentScheduler component. SchedulerComponentName = "deployment-scheduler" // SchedulerEventBufferSize is the size of the event subscription buffer for the scheduler. // Moderate-volume component handling template, validation, and discovery events. // Named with "Scheduler" prefix to avoid conflict with EventBufferSize in this package. SchedulerEventBufferSize = busevents.StandardSubscriberBuffer )
const (
// DriftMonitorComponentName is the unique identifier for the drift prevention monitor component.
DriftMonitorComponentName = "drift-monitor"
)
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AckedPlanSink ¶
type AckedPlanSink interface {
SetAckedPlan(*renderplan.Plan)
}
AckedPlanSink receives the plan the fleet confirmed it is running. The renderer implements it; the deployer calls it after a deployment lands.
type Component ¶
type Component struct {
*component.Base
*component.ReadySignal
// contains filtered or unexported fields
}
Component implements the deployer component.
Event subscriptions:
- DeploymentScheduledEvent: apply the render to the scheduled endpoints
- DeploymentCancelRequestEvent: cancel an in-progress deployment through a separate control loop that stays responsive while execution blocks
func New ¶
func New(eventBus *busevents.EventBus, logger *slog.Logger, syncTimeout time.Duration, domainMetrics *metrics.Metrics) *Component
New creates a new Deployer component.
syncTimeout bounds one pod's apply; the agent's own reload deadline is a chart-templated agent flag, not a client timeout. domainMetrics may be nil in tests; the per-pod counters are then not recorded.
func (*Component) CoalescesOn ¶
CoalescesOn implements component.CoalescingHandler: after each dispatch, the embedded component.Base drains the subscription channel and processes only the LATEST pending coalescible DeploymentScheduledEvent ("latest wins").
This coalescing is load-bearing: deployment is single-threaded, but the validator + scheduler upstream can fire many DeploymentScheduledEvents during a single deployment. Without it, the deployer would process every queued event in FIFO order — deploying the OLDEST pending config first and falling further and further behind under load.
func (*Component) Drain ¶
Drain ends this term's deployments and returns once the one in flight has published its receipt, provided the term still holds the Lease.
func (*Component) HandleEvent ¶
HandleEvent implements component.EventHandler: it routes events to the appropriate handler.
func (*Component) HealthCheck ¶
HealthCheck implements the lifecycle.HealthChecker interface. Returns an error if the component appears to be stalled (processing for > timeout). Returns nil when idle - idle is always healthy for event-driven components.
func (*Component) SetValidatedOccurrence ¶
func (c *Component) SetValidatedOccurrence(occurrence *rendercycle.Occurrence)
SetValidatedOccurrence records one exact render execution the gate passed.
type DeployStack ¶
type DeployStack struct {
Deployer *Component
Scheduler *DeploymentScheduler
DriftMonitor *DriftPreventionMonitor
}
DeployStack is the deploy-side component set, already wired together.
func NewDeployStack ¶
func NewDeployStack( eventBus *busevents.EventBus, cfg *coreconfig.Config, logger *slog.Logger, domainMetrics *metrics.Metrics, renderInputs RenderInputs, fence LeadershipFence, tls *transportsecurity.Source, ) *DeployStack
NewDeployStack builds the three deploy-side components and connects them to the metrics registry, the leadership fence and the render inputs.
The wiring lives here so a caller cannot forget one of the connections. domainMetrics is required. renderInputs and fence may be nil: the renderer then keeps rendering from its own plans and the local HAProxy probe, and applies are fenced at epoch zero (single writer, leader election disabled).
func (*DeployStack) EnableRetainedRecovery ¶
func (s *DeployStack) EnableRetainedRecovery(store RetainedStore, checker RetainedChecker, template *v1.HAProxyTemplateConfig, domainMetrics *metrics.Metrics, leaseName string)
EnableRetainedRecovery wires the leader's read, validation and bootstrap path.
type DeploymentScheduler ¶
type DeploymentScheduler struct {
*component.ReadySignal
// contains filtered or unexported fields
}
DeploymentScheduler decides which render is deployed next, and when.
It subscribes to events that trigger deployments, maintains the state of rendered and validated configurations, and holds a new render while the fleet's paced reloads are still pending. One deployment in flight is the only rate limit it applies; reload pacing lives in the agent.
Event subscriptions:
- TemplateRenderedEvent: Cache the render and schedule deployment
- RenderGateCompletedEvent: Move the gate's latch; a pass releases a held render
- ValidationFailedEvent: Deploy cached config for drift prevention fallback
- HAProxyPodsDiscoveredEvent: Update endpoints and schedule deployment
The component publishes DeploymentScheduledEvent when a deployment should execute.
func (*DeploymentScheduler) Drain ¶
func (s *DeploymentScheduler) Drain(ctx context.Context) error
Drain stops dispatching any plan other than the one last dispatched, which is the plan the deployment intent names, and returns once that deployment and its pending-reload follow-ups have completed: a paced reload confirms its worker receipt only on the follow-up.
func (*DeploymentScheduler) HealthCheck ¶
func (s *DeploymentScheduler) HealthCheck() error
HealthCheck implements the lifecycle.HealthChecker interface. Returns an error if the component appears to be stalled (processing for > timeout). Returns nil when idle (not processing) - idle is always healthy for event-driven components.
func (*DeploymentScheduler) Name ¶
func (s *DeploymentScheduler) Name() string
Name returns the unique identifier for this component. Implements the lifecycle.Component interface.
func (*DeploymentScheduler) Start ¶
func (s *DeploymentScheduler) Start(ctx context.Context) error
Start begins the deployment scheduler's event loop.
This method blocks until the context is cancelled or an error occurs. It subscribes to events when called (after leadership is acquired).
Parameters:
- ctx: Context for cancellation and lifecycle management
Returns:
- nil when context is cancelled (graceful shutdown)
- Error only in exceptional circumstances
type DriftPreventionMonitor ¶
type DriftPreventionMonitor struct {
*component.ReadySignal
// contains filtered or unexported fields
}
DriftPreventionMonitor triggers periodic reconciliation to prevent configuration drift in HAProxy pods.
When no deployment has occurred within the configured interval, it publishes a DriftPreventionTriggeredEvent to trigger reconciliation. This helps detect and correct configuration drift caused by anything writing to the pod's file tree or manual changes.
This is a leader-only component that starts when leadership is acquired. Only the leader needs drift prevention since only the leader deploys. The Reconciler triggers fresh reconciliation on BecameLeaderEvent to provide current state.
Event subscriptions:
- DeploymentCompletedEvent: Reset drift prevention timer
- LostLeadershipEvent: Stop drift timer when losing leadership
The component publishes DriftPreventionTriggeredEvent when drift prevention is needed.
func NewDriftPreventionMonitor ¶
func NewDriftPreventionMonitor(eventBus *busevents.EventBus, logger *slog.Logger, driftPreventionInterval time.Duration) *DriftPreventionMonitor
NewDriftPreventionMonitor creates a new DriftPreventionMonitor component.
As a leader-only component, subscription happens in Start() after leadership is acquired, not during construction.
Parameters:
- eventBus: The EventBus for subscribing to events and publishing triggers
- logger: Structured logger for component logging
- driftPreventionInterval: Interval after which to trigger drift prevention deployment
Returns:
- A new DriftPreventionMonitor instance ready to be started
func (*DriftPreventionMonitor) HealthCheck ¶
func (m *DriftPreventionMonitor) HealthCheck() error
HealthCheck implements the lifecycle.HealthChecker interface. Returns an error if the component appears to be stalled (no timer tick for > stallTimeout). For a timer-based component like DriftPreventionMonitor, a healthy state means the timer is firing at the expected interval.
func (*DriftPreventionMonitor) Name ¶
func (m *DriftPreventionMonitor) Name() string
Name returns the unique identifier for this component. Implements the lifecycle.Component interface.
func (*DriftPreventionMonitor) Start ¶
func (m *DriftPreventionMonitor) Start(ctx context.Context) error
Start begins the drift prevention monitor's event loop.
This method blocks until the context is cancelled or an error occurs. As a leader-only component, it subscribes to events when started (after leadership is acquired).
Event handling:
- DeploymentCompletedEvent: Resets the drift prevention timer
- LostLeadershipEvent: Stops drift timer when losing leadership
- Drift timer expiration: Publishes DriftPreventionTriggeredEvent
The component runs until the context is cancelled, at which point it performs cleanup and returns.
Parameters:
- ctx: Context for cancellation and lifecycle management
Returns:
- nil when context is cancelled (graceful shutdown)
- Error only in exceptional circumstances
type FleetCapabilitiesSink ¶
type FleetCapabilitiesSink interface {
SetCapabilities(dataplane.Capabilities)
}
FleetCapabilitiesSink receives what the fleet's HAProxy version supports. The renderer implements it; templates read the result as `capabilities`.
type LeadershipFence ¶
type LeadershipFence interface {
Identity() string
LeaderEpoch() uint64
// Reclaim lifts the epoch past one a pod already accepted. It errors when
// a newer leader — not a regressed counter — is behind the refusal, which
// is the one case where the pod is right and this controller must stop.
Reclaim(ctx context.Context, floor uint64) (uint64, error)
// StandDown gives leadership up so a fresh term claims a fresh epoch.
StandDown(reason string)
}
LeadershipFence is the current leadership term: who this controller is, the epoch every apply it sends is fenced by, and the two answers to a pod that refuses that epoch. A pod that has seen a higher epoch refuses this controller's writes.
type RenderInputs ¶
type RenderInputs interface {
AckedPlanSink
FleetCapabilitiesSink
}
RenderInputs is what the deploy side feeds back into the next render: the plan the fleet ACKed and the capabilities its HAProxy version supports. The renderer implements both.
type RetainedChecker ¶
type RetainedChecker interface {
CheckOutput(context.Context, *renderoutput.Snapshot, string) error
}
RetainedChecker checks a complete snapshot with the current HAProxy binary.
type RetainedIntentStore ¶
type RetainedIntentStore interface {
ClaimDeploymentAuthority(context.Context, *configpublisher.DeploymentAuthority) error
RecordDeploymentIntent(context.Context, *configpublisher.DeploymentAuthority, string, string) error
CheckDeploymentIntent(context.Context, *configpublisher.DeploymentAuthority, string, string) error
CheckDeploymentAuthority(context.Context, *configpublisher.DeploymentAuthority) error
}
RetainedIntentStore fences writers and records output identity before apply.
type RetainedLoader ¶
type RetainedLoader interface {
LoadRetained(context.Context, string, string, types.UID) ([]configpublisher.RetainedConfig, error)
}
RetainedLoader reads complete, acknowledged snapshots without publishing.
type RetainedStore ¶
type RetainedStore interface {
RetainedLoader
RetainedIntentStore
}
RetainedStore provides snapshots and the durable deployment barrier.
Source Files
¶
- agent_clients.go
- apply.go
- baseline_seed.go
- component.go
- convergence.go
- deployment.go
- deployment_lifecycle.go
- deployment_results.go
- diff_memo.go
- drift_monitor.go
- file_patch.go
- fleet_capabilities.go
- output_identity.go
- plan_cache.go
- plan_keeper.go
- reload_observation.go
- retained.go
- revert.go
- scheduler.go
- scheduler_drain.go
- scheduler_handlers.go
- scheduler_logic.go
- stack.go
- validated_plans.go