Documentation
¶
Overview ¶
Package controller provides the main controller orchestration for the HAProxy template ingress controller.
The controller follows an event-driven architecture with a reinitialization loop: 1. Fetch and validate initial configuration 2. Create EventBus and components 3. Start components and watchers 4. Wait for configuration changes 5. Reinitialize on valid config changes
Index ¶
- Constants
- func NewClusterSchemaFetcher(apiext apiextensionsclientset.Interface, d discovery.DiscoveryInterface) schemafetcher.Fetcher
- func ResolveLibraryRefs(ctx context.Context, k8sClient *client.Client, ...) (sources []*unstructured.Unstructured, unresolved []string, err error)
- func Run(ctx context.Context, k8sClient *client.Client, crdName string, ...) error
- func RunTypeBootstrap(ctx context.Context, cfg *config.Config, fetcher schemafetcher.Fetcher, ...) (*typebootstrap.Result, error)
- func SetBuildInfo(version, haproxyVersion string)
- func SetBuildSourceHash(value string)
- type DiscoveryServedChecker
- func (c *DiscoveryServedChecker) FieldServed(apiVersion, resources, fieldPath string) (bool, error)
- func (c *DiscoveryServedChecker) IsNamespaced(apiVersion, resources string) bool
- func (c *DiscoveryServedChecker) IsServed(apiVersion, resources string) bool
- func (c *DiscoveryServedChecker) TransientErr() error
- type InitialConfigBundle
- type StateCache
- func (sc *StateCache) GetAuxiliaryFiles() (*dataplane.AuxiliaryFiles, time.Time, error)
- func (sc *StateCache) GetConfig() (*coreconfig.Config, string, error)
- func (sc *StateCache) GetCredentials() (*coreconfig.Credentials, string, error)
- func (sc *StateCache) GetErrors() (*debug.ErrorSummary, error)
- func (sc *StateCache) GetPipelineStatus() (*debug.PipelineStatus, error)
- func (sc *StateCache) GetRenderedConfig() (string, time.Time, error)
- func (sc *StateCache) GetResourceCounts() (map[string]int, error)
- func (sc *StateCache) GetResourcesByType(resourceType string) ([]any, error)
- func (sc *StateCache) GetValidatedConfig() (*debug.ValidatedConfigInfo, error)
- func (sc *StateCache) HandleEvent(event busevents.Event)
- type WebhookAdmissionTimeouts
Constants ¶
const ( // RetryDelay is the duration to wait before retrying after an iteration failure. RetryDelay = 5 * time.Second // ConfigPollInterval is the interval for polling HAProxyTemplateConfig availability. ConfigPollInterval = 5 * time.Second // DebugEventBufferSize is the size of the event buffer for debug/introspection. DebugEventBufferSize = busevents.DebugSubscriberBuffer // ShutdownTimeout is the maximum time to wait for goroutines to finish during shutdown. // Set to 25s to allow clean exit before Kubernetes' default 30s terminationGracePeriodSeconds. ShutdownTimeout = 25 * time.Second // ShutdownProgressInterval is how often to log progress during shutdown. ShutdownProgressInterval = 5 * time.Second // ProcessShutdownTimeout leaves one second before the chart's SIGKILL deadline. ProcessShutdownTimeout = 89 * time.Second )
const ( // ReadinessPath and LivenessPath judge the serving iteration; /healthz // keeps judging the newest one (ADR-0028). ReadinessPath = "/readyz" LivenessPath = "/livez" )
Variables ¶
This section is empty.
Functions ¶
func NewClusterSchemaFetcher ¶
func NewClusterSchemaFetcher(apiext apiextensionsclientset.Interface, d discovery.DiscoveryInterface) schemafetcher.Fetcher
NewClusterSchemaFetcher composes the apiextensions CRD getter and the discovery-backed OpenAPI v3 provider into the live-cluster schema fetcher. The controller's iteration wiring and the CLI commands that reach a live cluster both build their schema access through this entry point. A cached d (memory.NewMemCacheClient) answers every CRD's plural from one discovery fetch.
func ResolveLibraryRefs ¶
func ResolveLibraryRefs( ctx context.Context, k8sClient *client.Client, libraryGVR schema.GroupVersionResource, config *unstructured.Unstructured, ) (sources []*unstructured.Unstructured, unresolved []string, err error)
ResolveLibraryRefs fetches the HAProxyTemplateLibrary a config references, in merge order, and returns them followed by the config itself — the config is last so its inline content wins over every referenced snippet.
A reference resolves only when the object exists AND its spec.revision equals the revision the reference names. Both strings come from whoever wrote the objects; nothing here derives a revision from content, so an operator editing a snippet in place keeps a resolving reference while a half-applied set does not. Unresolved references are returned for the caller to report, not treated as an error.
func Run ¶
func Run( ctx context.Context, k8sClient *client.Client, crdName string, secretName, webhookCertDir string, webhookAdmissionTimeouts WebhookAdmissionTimeouts, debugPort int, agentTLS *transportsecurity.Source, ) error
Run is the main entry point for the controller.
It performs initial configuration fetching and validation, then enters a reinitialization loop where it responds to configuration changes by restarting with the new configuration.
The controller uses an event-driven architecture:
- EventBus coordinates all components
- SingleWatcher monitors HAProxyTemplateConfig CRD and Secret
- Components react to events and publish results
- ConfigChangeHandler detects validated config changes and signals reinitialization
Parameters:
- ctx: Context for cancellation (SIGTERM, SIGINT, etc.)
- k8sClient: Kubernetes client for API access
- crdName: Name of the HAProxyTemplateConfig this controller serves (later wins); the last one is the primary, see primaryConfigName
- secretName: Name of the Secret containing the HAPTIC agent credentials
- webhookCertDir: Directory holding the webhook TLS cert (tls.crt/tls.key); empty disables the webhook
- webhookAdmissionTimeouts: Controller-side admission deadlines. Zero values use the webhook component defaults.
- debugPort: Port for debug HTTP server (0 to disable)
Returns:
- Error if the controller cannot start or encounters a fatal error
- nil if the context is cancelled (graceful shutdown)
func RunTypeBootstrap ¶
func RunTypeBootstrap( ctx context.Context, cfg *config.Config, fetcher schemafetcher.Fetcher, d discovery.DiscoveryInterface, logger *slog.Logger, ) (*typebootstrap.Result, error)
RunTypeBootstrap is the schema-source-agnostic core of the live type bootstrap: GVK resolution through the supplied discovery interface, schema acquisition through the supplied fetcher. The controller's iteration startup reaches it via runTypeBootstrap (which builds both from the iteration's K8s client); a CLI can call it directly with clients built from the operator's kubeconfig.
func SetBuildInfo ¶
func SetBuildInfo(version, haproxyVersion string)
SetBuildInfo configures version information exposed via the haptic_build_info Prometheus metric. Must be called before Run() to take effect.
Parameters:
- version: Controller version (e.g., "0.1.0-alpha.10")
- haproxyVersion: HAProxy version the controller was built for (e.g., "3.2")
func SetBuildSourceHash ¶ added in v0.7.0
func SetBuildSourceHash(value string)
SetBuildSourceHash sets the immutable source identity before Run starts.
Types ¶
type DiscoveryServedChecker ¶
type DiscoveryServedChecker struct {
// contains filtered or unexported fields
}
DiscoveryServedChecker answers "is this plural resource served at this group/version?" from live apiserver discovery, memoizing one discovery call per distinct group/version. It doubles as the SchemaFieldChecker for RequiresFields stripping: the same discovery answer carries the Kind for each served plural, which the schema fetcher needs to probe the resolved schema's fields. Instances are single-use snapshots: build a fresh one per resolution so CRDs installed or upgraded between config loads are seen. Not safe for concurrent use (resolution is sequential).
Only an authoritative NotFound counts as "unserved". A TRANSIENT discovery error (apiserver blip, aggregated-API hiccup) is recorded in transientErr instead: silently treating it as unserved would strip optional features — and bounce the controller through a spurious reinit — on every blip. The caller checks TransientErr() after resolution and fails the whole resolution, which the iteration retry loop (or the next CRD event) re-attempts safely. Schema-fetch errors during FieldServed fail the resolution directly (the SchemaFieldChecker contract).
func NewDiscoveryServedChecker ¶
func NewDiscoveryServedChecker(ctx context.Context, d discovery.DiscoveryInterface, fetcher schemafetcher.Fetcher, logger *slog.Logger) *DiscoveryServedChecker
func (*DiscoveryServedChecker) FieldServed ¶
func (c *DiscoveryServedChecker) FieldServed(apiVersion, resources, fieldPath string) (bool, error)
FieldServed implements coreconfig.SchemaFieldChecker: it fetches the resolved schema for the resource (CRD openAPIV3Schema or aggregated OpenAPI v3, via the cluster fetcher) and walks it for the dot-path. Every error — transient fetch failure or a genuinely missing schema for a resource discovery says is served — fails the resolution rather than silently stripping, mirroring the fail-closed type-bootstrap contract.
func (*DiscoveryServedChecker) IsNamespaced ¶ added in v0.7.0
func (c *DiscoveryServedChecker) IsNamespaced(apiVersion, resources string) bool
IsNamespaced implements coreconfig.NamespaceScopeChecker.
func (*DiscoveryServedChecker) IsServed ¶
func (c *DiscoveryServedChecker) IsServed(apiVersion, resources string) bool
IsServed implements coreconfig.ServedVersionChecker.
func (*DiscoveryServedChecker) TransientErr ¶
func (c *DiscoveryServedChecker) TransientErr() error
TransientErr returns the first non-NotFound discovery error observed, or nil when every answer was authoritative.
type InitialConfigBundle ¶
type InitialConfigBundle struct {
Config *coreconfig.Config
CRD *v1alpha1.HAProxyTemplateConfig
Credentials *coreconfig.Credentials
// ConfigVersion identifies the whole merged set, not just the primary
// config — see conversion.CompositeVersion. The bootstrap guard compares
// it for equality, so it has to change when ANY member changes.
ConfigVersion string
CredentialsVersion string
// Sources names the HAProxyTemplateConfig objects that receive status, at the
// generation the merge observed. Libraries are a different kind and get none.
Sources []events.ConfigSourceRef
}
fetchAndValidateInitialConfig fetches, parses, and validates the initial HAProxyTemplateConfig CRD and credentials Secret.
Returns the validated configuration and credentials, or an error if any step fails. InitialConfigBundle holds the parsed initial CRD / Secret values plus the resource versions of the underlying Secrets, so the iteration startup can wire bootstrap-version filtering for ConfigChangeHandler.
type StateCache ¶
StateCache caches controller state by subscribing to events.
This component implements the debug.StateProvider interface and provides thread-safe access to the controller's internal state for debug purposes.
It subscribes to key events and updates its cached state accordingly:
- ConfigValidatedEvent → updates config cache
- CredentialsUpdatedEvent → updates credentials cache
- TemplateRenderedEvent → updates rendered config cache
- ReconciliationTriggeredEvent → updates pipeline trigger state
- RenderGateCompletedEvent/ValidationFailedEvent → updates validation state
- DeploymentStartedEvent/CompletedEvent → updates deployment state
- InstanceDeploymentFailedEvent → tracks failed endpoints
func NewStateCache ¶
func NewStateCache(eventBus *busevents.EventBus, resourceWatcher *resourcewatcher.ResourceWatcherComponent, logger *slog.Logger) *StateCache
NewStateCache creates a new state cache component.
The StateCache subscribes to the EventBus in the constructor (before EventBus.Start()) to ensure proper startup synchronization and receive all buffered startup events.
Usage:
stateCache := NewStateCache(eventBus, resourceWatcher, logger) go stateCache.Start(ctx) // Process events in background eventBus.Start() // Release buffered events
func (*StateCache) GetAuxiliaryFiles ¶
func (sc *StateCache) GetAuxiliaryFiles() (*dataplane.AuxiliaryFiles, time.Time, error)
GetAuxiliaryFiles implements debug.StateProvider.
func (*StateCache) GetConfig ¶
func (sc *StateCache) GetConfig() (*coreconfig.Config, string, error)
GetConfig implements debug.StateProvider.
func (*StateCache) GetCredentials ¶
func (sc *StateCache) GetCredentials() (*coreconfig.Credentials, string, error)
GetCredentials implements debug.StateProvider.
func (*StateCache) GetErrors ¶
func (sc *StateCache) GetErrors() (*debug.ErrorSummary, error)
GetErrors implements debug.StateProvider.
func (*StateCache) GetPipelineStatus ¶
func (sc *StateCache) GetPipelineStatus() (*debug.PipelineStatus, error)
GetPipelineStatus implements debug.StateProvider.
func (*StateCache) GetRenderedConfig ¶
func (sc *StateCache) GetRenderedConfig() (string, time.Time, error)
GetRenderedConfig implements debug.StateProvider.
func (*StateCache) GetResourceCounts ¶
func (sc *StateCache) GetResourceCounts() (map[string]int, error)
GetResourceCounts implements debug.StateProvider.
func (*StateCache) GetResourcesByType ¶
func (sc *StateCache) GetResourcesByType(resourceType string) ([]any, error)
GetResourcesByType implements debug.StateProvider.
For `store: on-demand` types the result is the warm-cache subset only, not the full tracked set (see the partial-result contract on the interface declaration and listResources below). GetResourceCounts() remains the authoritative total.
func (*StateCache) GetValidatedConfig ¶
func (sc *StateCache) GetValidatedConfig() (*debug.ValidatedConfigInfo, error)
GetValidatedConfig implements debug.StateProvider.
func (*StateCache) HandleEvent ¶
func (sc *StateCache) HandleEvent(event busevents.Event)
HandleEvent implements component.EventHandler: it processes events and updates cached state.
type WebhookAdmissionTimeouts ¶
WebhookAdmissionTimeouts contains the controller-side deadline for watched-resource admission. (HAProxyTemplateConfig admission no longer exists — ADR-0016.)
Source Files
¶
- build_identity.go
- config.go
- controller.go
- currentfiles.go
- effectiveconfig.go
- event_delivery.go
- helpers.go
- infrastructure.go
- input_isolation.go
- iteration.go
- leader.go
- probes.go
- publishedauxfiles.go
- reconciliation.go
- reload_authority.go
- shared_cleanup.go
- shutdown.go
- siblings.go
- statecache.go
- statecache_providers.go
- typebootstrap_clients.go
- typebootstrap_wiring.go
- watchers.go
- webhook.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package buffers provides fixed buffer sizes for event subscriptions.
|
Package buffers provides fixed buffer sizes for event subscriptions. |
|
Package coalesce provides utilities for event coalescing in controller components.
|
Package coalesce provides utilities for event coalescing in controller components. |
|
Package commentator provides the Event Commentator pattern for domain-aware logging.
|
Package commentator provides the Event Commentator pattern for domain-aware logging. |
|
Package component provides event subscription, dispatch, panic recovery, and shutdown.
|
Package component provides event subscription, dispatch, panic recovery, and shutdown. |
|
Package configtest runs a HAProxyTemplateConfig's embedded validationTests against an already-built engine, bounded by a timeout.
|
Package configtest runs a HAProxyTemplateConfig's embedded validationTests against an already-built engine, bounded by a timeout. |
|
Package crdwatch reinitializes the controller when the CustomResourceDefinitions backing watched resources change.
|
Package crdwatch reinitializes the controller when the CustomResourceDefinitions backing watched resources change. |
|
Package debug provides controller-specific debug variable implementations.
|
Package debug provides controller-specific debug variable implementations. |
|
Package deployer applies a validated render to the HAProxy fleet through the HAPTIC agent that owns each pod's file tree.
|
Package deployer applies a validated render to the HAProxy fleet through the HAPTIC agent that owns each pod's file tree. |
|
Package diagnostics collects content-free evidence about a HAPTIC fleet.
|
Package diagnostics collects content-free evidence about a HAPTIC fleet. |
|
Package discovery provides the Discovery event adapter component.
|
Package discovery provides the Discovery event adapter component. |
|
Package dryrunvalidator implements the DryRunValidator that performs dry-run reconciliation for webhook validation.
|
Package dryrunvalidator implements the DryRunValidator that performs dry-run reconciliation for webhook validation. |
|
Package eventemitter publishes Kubernetes Events for rendered configuration, deployment failures, and rejected watched inputs.
|
Package eventemitter publishes Kubernetes Events for rendered configuration, deployment failures, and rejected watched inputs. |
|
Package events contains all domain event type definitions for the HAPTIC controller.
|
Package events contains all domain event type definitions for the HAPTIC controller. |
|
Package helpers provides shared utility functions for the controller layer.
|
Package helpers provides shared utility functions for the controller layer. |
|
Package httpstore provides the event adapter for HTTP resource fetching.
|
Package httpstore provides the event adapter for HTTP resource fetching. |
|
Package indextracker provides the IndexSynchronizationTracker that monitors resource watcher synchronization and publishes an event when all are synced.
|
Package indextracker provides the IndexSynchronizationTracker that monitors resource watcher synchronization and publishes an event when all are synced. |
|
Package inputisolation selects independently valid watched-resource updates.
|
Package inputisolation selects independently valid watched-resource updates. |
|
Package leadership provides utilities for handling leadership transitions in event-driven components.
|
Package leadership provides utilities for handling leadership transitions in event-driven components. |
|
Package names provides well-known string constants used across the controller layer.
|
Package names provides well-known string constants used across the controller layer. |
|
Package pipeline provides the render-validate pipeline for HAProxy configuration.
|
Package pipeline provides the render-validate pipeline for HAProxy configuration. |
|
Package pluggablevalidator implements the controller-side client for the pluggable-validator-sidecar wire protocol.
|
Package pluggablevalidator implements the controller-side client for the pluggable-validator-sidecar wire protocol. |
|
testutil
Package testutil provides a fixture unix-socket server for exercising the pluggablevalidator client without spinning up a real haproxy-spoa-hub sidecar.
|
Package testutil provides a fixture unix-socket server for exercising the pluggablevalidator client without spinning up a real haproxy-spoa-hub sidecar. |
|
Package proposalvalidator validates hypothetical configuration changes.
|
Package proposalvalidator validates hypothetical configuration changes. |
|
Package reconciler implements the Reconciler component that triggers reconciliation events on resource changes.
|
Package reconciler implements the Reconciler component that triggers reconciliation events on resource changes. |
|
Package rendercontext provides a centralized builder for template rendering contexts.
|
Package rendercontext provides a centralized builder for template rendering contexts. |
|
Package rendercycle binds one rendered output to every effect produced by the same controller reconciliation under an authenticated immutable root.
|
Package rendercycle binds one rendered output to every effect produced by the same controller reconciliation under an authenticated immutable root. |
|
Package rendergate runs the controller's own `haproxy -c` over each render, off the reconcile wall clock.
|
Package rendergate runs the controller's own `haproxy -c` over each render, off the reconcile wall clock. |
|
Package resourceapplier reconciles template-declared Kubernetes resources via Server-Side Apply (SSA).
|
Package resourceapplier reconciles template-declared Kubernetes resources via Server-Side Apply (SSA). |
|
Package resourcewatcher provides the ResourceWatcherComponent that creates and manages watchers for all Kubernetes resources defined in the controller configuration.
|
Package resourcewatcher provides the ResourceWatcherComponent that creates and manages watchers for all Kubernetes resources defined in the controller configuration. |
|
Package statusapplier applies template-driven status patches to Kubernetes resources.
|
Package statusapplier applies template-driven status patches to Kubernetes resources. |
|
Package testrunner implements validation test execution for HAProxyTemplateConfig.
|
Package testrunner implements validation test execution for HAProxyTemplateConfig. |
|
Package testutil provides shared test helpers for controller package tests.
|
Package testutil provides shared test helpers for controller package tests. |
|
Package throttle provides leading-edge refractory throttle helpers used by controller components that bound their write rate to slow downstream systems (e.g.
|
Package throttle provides leading-edge refractory throttle helpers used by controller components that bound their write rate to slow downstream systems (e.g. |
|
Package timeouts provides shared timeout constants used across controller sub-packages.
|
Package timeouts provides shared timeout constants used across controller sub-packages. |
|
Package timers provides safe timer management for event-driven controller components.
|
Package timers provides safe timer management for event-driven controller components. |
|
Package typebootstrap orchestrates the typed-watched-resources pipeline at controller startup.
|
Package typebootstrap orchestrates the typed-watched-resources pipeline at controller startup. |
|
Package validation provides pure validation services for HAProxy configuration.
|
Package validation provides pure validation services for HAProxy configuration. |
|
Package warmer keeps a follower's incremental render graph warm.
|
Package warmer keeps a follower's incremental render graph warm. |
|
Package webhook connects the admission server to controller validation.
|
Package webhook connects the admission server to controller validation. |