Documentation
¶
Index ¶
- Variables
- func BuildAuxiliaryFileSnapshot(authority *renderartifact.Authority, previous *renderartifact.Snapshot, ...) (*renderartifact.Snapshot, error)
- func BuildAuxiliaryFileSnapshotWithRuntimePaths(authority *renderartifact.Authority, previous *renderartifact.Snapshot, ...) (*renderartifact.Snapshot, error)
- func BuildAuxiliaryFileTransition(authority *renderartifact.Authority, previous *renderartifact.Snapshot, ...) (*renderartifact.Snapshot, *renderartifact.Delta, error)
- func BuildAuxiliaryFileTransitionWithRuntimePaths(authority *renderartifact.Authority, previous *renderartifact.Snapshot, ...) (*renderartifact.Snapshot, *renderartifact.Delta, error)
- func ComputeContentChecksum(haproxyConfig string, auxFiles *AuxiliaryFiles) string
- func ComputeSnapshotContentChecksum(haproxyConfig string, snapshot *renderartifact.Snapshot) (string, error)
- func ContentEqual(leftConfig string, leftAux *AuxiliaryFiles, rightConfig string, ...) bool
- func SetHAProxyExecutor(e HAProxyExecutor) (restore func())
- func SimplifyValidationError(err error) string
- func SnapshotContentEqual(leftConfig string, left *renderartifact.Snapshot, rightConfig string, ...) (bool, error)
- func SnapshotCurrentFiles(snapshot *renderartifact.Snapshot) (map[string]string, error)
- func ValidateConfigurationContext(ctx context.Context, mainConfig string, auxFiles *AuxiliaryFiles, ...) error
- func ValidateSemanticsContext(ctx context.Context, mainConfig string, auxFiles *AuxiliaryFiles, ...) error
- func ValidateSemanticsWithVerdicts(ctx context.Context, mainConfig string, auxFiles *AuxiliaryFiles, ...) (reused bool, err error)
- type AuxiliaryFiles
- type Capabilities
- type CheckGate
- type CheckVerdicts
- type Endpoint
- type HAProxyExecutor
- type PathConfig
- type RefusalError
- type ResolvedPaths
- type ValidationError
- type ValidationPaths
- type Version
Constants ¶
This section is empty.
Variables ¶
var ErrHAProxyRefused = errors.New("haproxy validation failed")
ErrHAProxyRefused reports that the haproxy binary judged a configuration and refused it. A check that could not run at all (no binary, unwritable temp tree, cancelled) does not wrap it, so callers never read an infrastructure failure as a verdict on the config.
Functions ¶
func BuildAuxiliaryFileSnapshot ¶
func BuildAuxiliaryFileSnapshot( authority *renderartifact.Authority, previous *renderartifact.Snapshot, files *AuxiliaryFiles, ) (*renderartifact.Snapshot, error)
BuildAuxiliaryFileSnapshot seals a complete legacy auxiliary-file set.
func BuildAuxiliaryFileSnapshotWithRuntimePaths ¶
func BuildAuxiliaryFileSnapshotWithRuntimePaths( authority *renderartifact.Authority, previous *renderartifact.Snapshot, files *AuxiliaryFiles, resolve func(renderartifact.Family, string) (string, error), ) (*renderartifact.Snapshot, error)
BuildAuxiliaryFileSnapshotWithRuntimePaths seals files with resolved plan paths.
func BuildAuxiliaryFileTransition ¶
func BuildAuxiliaryFileTransition( authority *renderartifact.Authority, previous *renderartifact.Snapshot, files *AuxiliaryFiles, ) (*renderartifact.Snapshot, *renderartifact.Delta, error)
BuildAuxiliaryFileTransition seals files and their exact transition from previous.
func BuildAuxiliaryFileTransitionWithRuntimePaths ¶
func BuildAuxiliaryFileTransitionWithRuntimePaths( authority *renderartifact.Authority, previous *renderartifact.Snapshot, files *AuxiliaryFiles, resolve func(renderartifact.Family, string) (string, error), ) (*renderartifact.Snapshot, *renderartifact.Delta, error)
BuildAuxiliaryFileTransitionWithRuntimePaths seals files with resolved plan paths.
func ComputeContentChecksum ¶
func ComputeContentChecksum(haproxyConfig string, auxFiles *AuxiliaryFiles) string
ComputeContentChecksum generates a SHA256 checksum covering the main HAProxy config and all auxiliary files (general files, map files, SSL certificates, CRT-list files).
The checksum is used for content deduplication to skip redundant processing when config content hasn't changed. Auxiliary file slices must be pre-sorted (by AuxiliaryFiles.Sort()) to ensure deterministic results regardless of insertion order.
Returns a hex-encoded 8-byte (16 character) checksum for brevity.
func ComputeSnapshotContentChecksum ¶
func ComputeSnapshotContentChecksum( haproxyConfig string, snapshot *renderartifact.Snapshot, ) (string, error)
ComputeSnapshotContentChecksum preserves ComputeContentChecksum's canonical legacy order.
func ContentEqual ¶
func ContentEqual(leftConfig string, leftAux *AuxiliaryFiles, rightConfig string, rightAux *AuxiliaryFiles) bool
ContentEqual compares every rendered byte and deployment-relevant file property.
func SetHAProxyExecutor ¶
func SetHAProxyExecutor(e HAProxyExecutor) (restore func())
SetHAProxyExecutor replaces the executor used by DetectLocalVersion and semantic validation, returning a function that restores the previous one. It exists so unit tests can substitute a fake instead of shelling out; production code must not call it. Prefer installing the fake once per test package (TestMain) — per-test installs interleave badly with t.Parallel.
func SimplifyValidationError ¶
SimplifyValidationError parses HAProxy validation errors and extracts the key information for user-friendly error messages.
Handles two types of validation errors:
Schema validation errors - OpenAPI spec violations: Input: "schema validation failed: configuration violates API schema constraints: ... Error at "/field": constraint" Output: "field constraint (got value)"
Semantic validation errors - HAProxy binary validation failures: Input: "semantic validation failed: configuration has semantic errors: haproxy validation failed: <context>" Output: "<context>" (preserves parseHAProxyError output with context lines)
Returns original error string if parsing fails.
func SnapshotContentEqual ¶
func SnapshotContentEqual( leftConfig string, left *renderartifact.Snapshot, rightConfig string, right *renderartifact.Snapshot, ) (bool, error)
SnapshotContentEqual compares exact main-config bytes and authenticated artifacts.
func SnapshotCurrentFiles ¶
func SnapshotCurrentFiles(snapshot *renderartifact.Snapshot) (map[string]string, error)
SnapshotCurrentFiles is the mutable currentFiles compatibility boundary.
func ValidateConfigurationContext ¶
func ValidateConfigurationContext(ctx context.Context, mainConfig string, auxFiles *AuxiliaryFiles, paths *ValidationPaths, skipDNSValidation bool, gate *CheckGate) error
ValidateConfigurationContext checks isolated validation files with HAProxy; a nil gate uses the shared default.
func ValidateSemanticsContext ¶
func ValidateSemanticsContext(ctx context.Context, mainConfig string, auxFiles *AuxiliaryFiles, paths *ValidationPaths, skipDNSValidation bool, gate *CheckGate) error
ValidateSemanticsContext checks the configuration with HAProxy; a nil gate uses the shared default.
func ValidateSemanticsWithVerdicts ¶
func ValidateSemanticsWithVerdicts(ctx context.Context, mainConfig string, auxFiles *AuxiliaryFiles, paths *ValidationPaths, skipDNSValidation bool, gate *CheckGate, verdicts *CheckVerdicts) (reused bool, err error)
ValidateSemanticsWithVerdicts is ValidateSemanticsContext answering an input set verdicts already judged, which reused reports. A verdict is reused only when paths.TempDir is a fresh, empty directory.
Types ¶
type AuxiliaryFiles ¶
type AuxiliaryFiles struct {
// GeneralFiles contains general-purpose files (error pages, custom response files, etc.)
GeneralFiles []auxiliaryfiles.GeneralFile
// SSLCertificates contains SSL certificates to sync to HAProxy SSL storage
SSLCertificates []auxiliaryfiles.SSLCertificate
// SSLCaFiles contains SSL CA certificate files for client/backend certificate verification
SSLCaFiles []auxiliaryfiles.SSLCaFile
// MapFiles contains map files for backend routing and other map-based features
MapFiles []auxiliaryfiles.MapFile
// CRTListFiles contains crt-list files for SSL certificate lists with per-certificate options
CRTListFiles []auxiliaryfiles.CRTListFile
}
AuxiliaryFiles are the files a render produces next to haproxy.cfg. They travel to the pod in the same apply as the configuration that names them.
func CanonicalizeAuxiliaryFiles ¶
func CanonicalizeAuxiliaryFiles(files *AuxiliaryFiles) (*AuxiliaryFiles, error)
CanonicalizeAuxiliaryFiles returns an independent, deterministically sorted file set and rejects definitions that collapse to one written file. The agent writes a file under the path the plan names, so the base name is the whole identity: two definitions that share one are the same file.
func CloneAuxiliaryFiles ¶
func CloneAuxiliaryFiles(files *AuxiliaryFiles) *AuxiliaryFiles
CloneAuxiliaryFiles returns an independently owned copy.
func DefaultAuxiliaryFiles ¶
func DefaultAuxiliaryFiles() *AuxiliaryFiles
DefaultAuxiliaryFiles returns an empty auxiliary files struct.
func MaterializeAuxiliaryFileSnapshot ¶
func MaterializeAuxiliaryFileSnapshot(snapshot *renderartifact.Snapshot) (*AuxiliaryFiles, error)
MaterializeAuxiliaryFileSnapshot returns a detached legacy value.
func (*AuxiliaryFiles) CurrentFiles ¶
func (af *AuxiliaryFiles) CurrentFiles() map[string]string
CurrentFiles projects CRD-backed auxiliary output into the currentFiles map. Secret-backed certificate and CA content is deliberately excluded.
func (*AuxiliaryFiles) Sort ¶
func (a *AuxiliaryFiles) Sort()
Sort sorts all auxiliary file slices in-place by their path/filename. This establishes a deterministic order so that downstream consumers (checksum, diff, etc.) can iterate directly without cloning or sorting.
type Capabilities ¶
type Capabilities struct {
// Storage capabilities
SupportsCrtList bool // crt-list files (3.2+)
SupportsMapStorage bool // map files (3.0+)
SupportsGeneralStorage bool // general files (3.0+)
SupportsSslCaFiles bool // CA files (3.2+)
SupportsSslCrlFiles bool // CRL files (3.2+)
// Configuration capabilities
SupportsHTTP2 bool // HTTP/2 (3.0+)
SupportsQUIC bool // QUIC/HTTP3 (3.0+)
SupportsQUICInitialRules bool // quic-initial rules (3.1+)
// Observability capabilities
SupportsLogProfiles bool // log-profile sections (3.1+)
SupportsTraces bool // traces section (3.1+)
// Certificate automation capabilities
SupportsAcmeProviders bool // acme sections (3.2+)
// Runtime capabilities
SupportsRuntimeMaps bool // runtime map operations (3.0+)
SupportsRuntimeServers bool // runtime server operations (3.0+)
}
Capabilities is what the fleet's HAProxy supports. The controller derives it from the lowest version its pods report, so a render never uses a feature the oldest pod would reject. Templates read the fields as snake_case keys (`capabilities.supports_crt_list`), which makes every field name a contract.
func CapabilitiesFromVersion ¶
func CapabilitiesFromVersion(v *Version) Capabilities
CapabilitiesFromVersion computes what a fleet running v supports. The controller's own binary seeds the value at startup; the deployer replaces it with the fleet minimum once the pods have reported.
type CheckGate ¶
type CheckGate struct {
// contains filtered or unexported fields
}
CheckGate bounds concurrent `haproxy -c` runs. Each gate owns one slot, so a caller with its own gate never queues behind another's checks; minInterval additionally caps a gate's duty cycle by spacing run starts.
The admission webhook and the reconcile gate hold separate gates on purpose: admission answers on a request deadline and must never wait out a fleet-sized config check.
func NewCheckGate ¶
NewCheckGate returns a gate with one slot. A non-positive minInterval disables the duty-cycle cap.
func NewCheckGateN ¶
NewCheckGateN returns a gate allowing `slots` concurrent checks (minimum 1). Use slots > 1 only for a batch of independent checks that should run across cores — the validationTests load gate, whose worker pool otherwise serializes every `haproxy -c` behind a single slot. Admission and the reconcile gate stay single-slot on purpose. The duty-cycle cap (minInterval) spaces run starts across all slots, so pair slots > 1 with minInterval == 0.
type CheckVerdicts ¶
type CheckVerdicts struct {
// contains filtered or unexported fields
}
CheckVerdicts remembers `haproxy -c` verdicts by a SHA-256 over the check's inputs: the binary, its arguments and environment, and the validation tree with the config and every file written into it. The check is deterministic over those, so an identical input set gets the answer HAProxy already gave instead of a second process. Only passes and refusals are remembered; a check that could not run is retried.
DNS is the input the key cannot cover, so a strict-DNS check (no -dr) is never answered from here. See ADR-0035.
func NewCheckVerdicts ¶
func NewCheckVerdicts(capacity int) *CheckVerdicts
NewCheckVerdicts returns a store holding the capacity most recently used verdicts (minimum 1).
type Endpoint ¶
type Endpoint struct {
// URL is the agent endpoint (e.g., "http://haproxy:5555").
URL string
// Username for basic authentication
Username string
// Password for basic authentication
Password string
// PodName is the Kubernetes pod name (for observability)
PodName string
// PodNamespace is the Kubernetes pod namespace (for observability)
PodNamespace string
// PodUID distinguishes replacements that reuse the same namespace and name.
PodUID string
// PodRuntimeID distinguishes container restarts and image changes within one pod UID.
PodRuntimeID string
// HAProxy version the pod's agent reported, cached after discovery
// admission. It decides this pod's runtime capabilities and, at its fleet
// minimum, the template ones. Zero values mean not yet detected.
DetectedMajorVersion int // Major version (e.g., 3)
DetectedMinorVersion int // Minor version (e.g., 4)
DetectedFullVersion string // Full version string (e.g., "3.4.3")
}
Endpoint is one HAProxy pod's agent: where to reach it and which pod it is.
func (*Endpoint) HasCachedVersion ¶
HasCachedVersion returns true if version info has been cached on this endpoint.
type HAProxyExecutor ¶
type HAProxyExecutor interface {
// Version returns the combined output of `haproxy -v`.
Version(ctx context.Context) (string, error)
// Check runs `haproxy <args...>` with the working directory set to
// workDir and returns the combined output. The working directory
// matters: semantic validation invokes haproxy with a relative config
// path so that relative file references inside the config resolve.
Check(ctx context.Context, workDir string, args ...string) ([]byte, error)
}
HAProxyExecutor abstracts execution of the local HAProxy binary so that unit tests never shell out to an external process. Production code uses the default binaryHAProxyExecutor; tests install a fake via SetHAProxyExecutor (most conveniently through pkg/dataplane/dataplanetest.InstallFakeHAProxy in a TestMain).
type PathConfig ¶
type PathConfig struct {
// MapsDir is the base path for HAProxy map files (e.g., /etc/haproxy/maps).
MapsDir string
// SSLDir is the base path for HAProxy SSL certificates (e.g., /etc/haproxy/ssl).
SSLDir string
// GeneralDir is the base path for HAProxy general files (e.g., /etc/haproxy/general).
GeneralDir string
// ConfigFile is the path to the HAProxy configuration file (e.g., /tmp/haproxy.cfg).
// Only used in validation contexts; can be empty for production paths.
ConfigFile string
}
PathConfig contains the base directory configuration for HAProxy auxiliary files. These are the raw filesystem paths before capability-based resolution.
type RefusalError ¶
type RefusalError struct {
// Causes are HAProxy's failure messages without process IDs, line numbers, or the
// check's working directory, so refusals of different renders compare by cause.
Causes []string
// contains filtered or unexported fields
}
RefusalError is a configuration refusal by the haproxy binary. It wraps ErrHAProxyRefused.
func (*RefusalError) Error ¶
func (e *RefusalError) Error() string
func (*RefusalError) Unwrap ¶
func (e *RefusalError) Unwrap() error
type ResolvedPaths ¶
type ResolvedPaths struct {
// MapsDir is the resolved path for HAProxy map files.
MapsDir string
// SSLDir is the resolved path for HAProxy SSL certificates.
SSLDir string
// CRTListDir is the resolved path for CRT-list files.
// Always equals GeneralDir because CRT-list files are stored as general files
// to avoid reload on create (native CRT-list API doesn't support skip_reload).
CRTListDir string
// GeneralDir is the resolved path for HAProxy general files.
GeneralDir string
// ConfigFile is the path to the HAProxy configuration file.
ConfigFile string
}
ResolvedPaths contains capability-aware resolved paths for HAProxy auxiliary files. This is the result of applying capability-based resolution to a PathConfig.
The key difference from PathConfig is that CRTListDir is always set to GeneralDir because CRT-list files are stored as general files to avoid reload on create.
func ResolvePaths ¶
func ResolvePaths(base PathConfig) *ResolvedPaths
ResolvePaths applies capability-based path resolution to base paths. This is the SINGLE SOURCE OF TRUTH for all capability-dependent path logic.
Currently handles:
- CRT-list storage: Always uses general directory because the native CRT-list API triggers reload on create without supporting skip_reload parameter. General file storage returns 201 without triggering reload.
func (*ResolvedPaths) ToValidationPaths ¶
func (r *ResolvedPaths) ToValidationPaths() *ValidationPaths
ToValidationPaths converts ResolvedPaths to ValidationPaths. Use this when you need ValidationPaths for HAProxy configuration validation. TempDir is derived from ConfigFile's parent directory (e.g., /tmp/validate-xxx/haproxy.cfg -> /tmp/validate-xxx).
type ValidationError ¶
type ValidationError struct {
// Phase indicates which validation phase failed: "syntax" or "semantic"
Phase string
// Message is the validation error message
Message string
// Cause is the underlying error
Cause error
}
ValidationError represents semantic validation failure from HAProxy.
func (*ValidationError) Error ¶
func (e *ValidationError) Error() string
Error implements the error interface.
func (*ValidationError) Unwrap ¶
func (e *ValidationError) Unwrap() error
Unwrap returns the underlying error for error unwrapping.
type ValidationPaths ¶
type ValidationPaths struct {
// TempDir is the root temp directory for validation files.
// The validator is responsible for cleaning this up after validation completes.
// This prevents race conditions where the renderer's cleanup runs before
// the async validator can use the validation files.
TempDir string
MapsDir string
SSLCertsDir string
CRTListDir string // Directory for CRT-list files (may differ from SSLCertsDir on HAProxy < 3.2)
GeneralStorageDir string
ConfigFile string
}
ValidationPaths holds the filesystem paths for HAProxy validation. They mirror the layout the agent writes on the pod, so a config that passes here resolves its files there.
type Version ¶
type Version struct {
Major int
Minor int
Patch int
Full string // Original version string, retained for logging
}
Version is a HAProxy version. Patch is best-effort: it is 0 when the source string carries only "major.minor" or a non-numeric patch segment.
func DetectLocalVersionContext ¶
DetectLocalVersionContext runs "haproxy -v" with caller cancellation.
func MinimumVersion ¶
MinimumVersion returns the lowest of the reported versions, ignoring the ones it cannot parse. It is how the controller derives what the whole fleet supports: during a rolling upgrade the oldest pod is the one that decides. Returns nil when no version is readable.
func ParseHAProxyVersionOutput ¶
ParseHAProxyVersionOutput parses the output of "haproxy -v" command. Expected format: "HAProxy version 3.2.9 2025/11/21 - https://haproxy.org/\n..." Returns extracted major.minor version.
func ParseVersionString ¶
ParseVersionString parses a version string like "3.3" or "3.3.0" into a Version. This is useful for parsing user-provided version constraints.
It is intentionally strict about the "v" prefix: a leading "v" is rejected rather than stripped, so an operator typo such as "v3.3.beta" surfaces as a parse error (callers then run the test anyway rather than silently skipping it). The original input is preserved verbatim in Version.Full so callers can echo it back unchanged.
func (*Version) Compare ¶
Compare orders two versions by major, then minor. Patch is INTENTIONALLY ignored: Compare answers series compatibility — the testrunner gating a test on minHAProxyVersion, or the deployer picking the fleet's lowest version. Returns -1 if v < other, 0 if same series, 1 if v > other.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
agent
|
|
|
agenttest
Package agenttest is an in-process HAPTIC agent: an httptest server that speaks pkg/dataplane/agent/api well enough to drive the controller's deployer without a container.
|
Package agenttest is an in-process HAPTIC agent: an httptest server that speaks pkg/dataplane/agent/api well enough to drive the controller's deployer without a container. |
|
api
Package api is the wire contract between the controller and the HAPTIC agent (the container that owns an HAProxy pod's file tree and runtime socket).
|
Package api is the wire contract between the controller and the HAPTIC agent (the container that owns an HAProxy pod's file tree and runtime socket). |
|
cli
Package cli turns the agent's typed ops into HAProxy runtime commands and runs them against the worker stats socket.
|
Package cli turns the agent's typed ops into HAProxy runtime commands and runs them against the worker stats socket. |
|
client
Package client is the controller's end of the HAPTIC agent wire contract (pkg/dataplane/agent/api): one pooled keep-alive HTTP client per pod, a state read and a streaming multipart apply.
|
Package client is the controller's end of the HAPTIC agent wire contract (pkg/dataplane/agent/api): one pooled keep-alive HTTP client per pod, a state read and a streaming multipart apply. |
|
files
Package files owns the manifest-managed file tree of an HAProxy pod: the mount probe, tree hashing, part verification, the backup journal and the transactional write.
|
Package files owns the manifest-managed file tree of an HAProxy pod: the mount probe, tree hashing, part verification, the backup journal and the transactional write. |
|
haproxytest
Package haproxytest serves an in-memory model of the HAProxy runtime over a worker stats socket and a master socket.
|
Package haproxytest serves an in-memory model of the HAProxy runtime over a worker stats socket and a master socket. |
|
server
Package server is the HAPTIC agent: an HTTP endpoint that owns one HAProxy pod's file tree and its runtime socket.
|
Package server is the HAPTIC agent: an HTTP endpoint that owns one HAProxy pod's file tree and its runtime socket. |
|
Package auxiliaryfiles holds the file types a render produces next to haproxy.cfg: general files (error pages, ACL files), SSL certificates, map files, crt-lists and CA files.
|
Package auxiliaryfiles holds the file types a render produces next to haproxy.cfg: general files (error pages, ACL files), SSL certificates, map files, crt-lists and CA files. |
|
Package dataplanetest provides test doubles for pkg/dataplane.
|
Package dataplanetest provides test doubles for pkg/dataplane. |
|
Package deployplan decides what one pod has to do to reach a render: run runtime ops, write files only, or reload.
|
Package deployplan decides what one pod has to do to reach a render: run runtime ops, write files only, or reload. |
|
Package planblob is the encoding of the opaque plan a pod stores and hands back on /v1/state: zstd over the plan's JSON, raw bytes on the wire.
|
Package planblob is the encoding of the opaque plan a pod stores and hands back on /v1/state: zstd over the plan's JSON, raw bytes on the wire. |
|
Package renderartifact holds authenticated immutable auxiliary render output.
|
Package renderartifact holds authenticated immutable auxiliary render output. |
|
Package renderoutput binds one rendered configuration to its exact plan and auxiliary artifacts under an authenticated immutable root.
|
Package renderoutput binds one rendered configuration to its exact plan and auxiliary artifacts under an authenticated immutable root. |
|
Package renderplan holds the structure a render declares about its own output: the ordered sections of haproxy.cfg, the backend records the generator emitted them from, the map entries, and the file set.
|
Package renderplan holds the structure a render declares about its own output: the ordered sections of haproxy.cfg, the backend records the generator emitted them from, the map entries, and the file set. |