Documentation
¶
Overview ¶
Package client provides a high-level wrapper around the generated HAProxy Dataplane API client.
This wrapper adds: - Multi-version support (v3.0, v3.1, v3.2, v3.3) and Enterprise variants - Runtime version detection - Capability-based feature detection - Raw config push (skip_reload + X-Runtime-Actions, or force_reload) - Auxiliary file storage operations (maps, SSL certs, general files, crt-lists) - Error handling and retry logic
Package client provides a multi-version wrapper for HAProxy Dataplane API clients.
This package implements the Kubernetes-style clientset pattern to support multiple HAProxy DataPlane API versions (3.0, 3.1, 3.2, 3.3) with: - Runtime version detection using /v3/info endpoint - Capability-based routing for graceful degradation - Version-specific client accessors
Index ¶
- Constants
- Variables
- func CheckResponse(resp *http.Response, operation string) error
- func IsEnterpriseVersion(version string) bool
- func SanitizeSSLCertName(name string) string
- func SanitizeStorageName(name string) string
- func UnsanitizeStorageName(name string) string
- func WithRetry[T any](ctx context.Context, config RetryConfig, fn func(attempt int) (T, error)) (T, error)
- type BackoffStrategy
- type CallFunc
- type Capabilities
- type Clientset
- func (c *Clientset) Capabilities() Capabilities
- func (c *Clientset) DetectedVersion() string
- func (c *Clientset) IsEnterprise() bool
- func (c *Clientset) MajorVersion() int
- func (c *Clientset) MinorVersion() int
- func (c *Clientset) PreferredClient() any
- func (c *Clientset) V30() *v30.Client
- func (c *Clientset) V30EE() *v30ee.Client
- func (c *Clientset) V31() *v31.Client
- func (c *Clientset) V31EE() *v31ee.Client
- func (c *Clientset) V32() *v32.Client
- func (c *Clientset) V32EE() *v32ee.Client
- func (c *Clientset) V33() *v33.Client
- type Config
- type DataplaneClient
- func (c *DataplaneClient) AddRuntimeCaFileEntry(ctx context.Context, name, content string) error
- func (c *DataplaneClient) BaseURL() string
- func (c *DataplaneClient) Capabilities() Capabilities
- func (c *DataplaneClient) Clientset() *Clientset
- func (c *DataplaneClient) CreateCRTListFile(ctx context.Context, name, content string) (string, error)
- func (c *DataplaneClient) CreateGeneralFile(ctx context.Context, path, content string) (string, error)
- func (c *DataplaneClient) CreateMapFile(ctx context.Context, name, content string) (string, error)
- func (c *DataplaneClient) CreateSSLCaFile(ctx context.Context, name, content string) (string, error)
- func (c *DataplaneClient) CreateSSLCertificate(ctx context.Context, name, content string) (string, error)
- func (c *DataplaneClient) DeleteCRTListFile(ctx context.Context, name string) error
- func (c *DataplaneClient) DeleteGeneralFile(ctx context.Context, path string) error
- func (c *DataplaneClient) DeleteMapFile(ctx context.Context, name string) error
- func (c *DataplaneClient) DeleteSSLCaFile(ctx context.Context, name string) error
- func (c *DataplaneClient) DeleteSSLCertificate(ctx context.Context, name string) error
- func (c *DataplaneClient) DetectedVersion() string
- func (c *DataplaneClient) Dispatch(ctx context.Context, call CallFunc[*http.Response]) (*http.Response, error)
- func (c *DataplaneClient) DispatchWithCapability(ctx context.Context, call CallFunc[*http.Response], ...) (*http.Response, error)
- func (c *DataplaneClient) GetAllCRTListFiles(ctx context.Context) ([]string, error)
- func (c *DataplaneClient) GetAllGeneralFiles(ctx context.Context) ([]string, error)
- func (c *DataplaneClient) GetAllMapFiles(ctx context.Context) ([]string, error)
- func (c *DataplaneClient) GetAllSSLCaFiles(ctx context.Context) ([]string, error)
- func (c *DataplaneClient) GetAllSSLCertificates(ctx context.Context) ([]string, error)
- func (c *DataplaneClient) GetCRTListFileContent(ctx context.Context, name string) (string, error)
- func (c *DataplaneClient) GetGeneralFileContent(ctx context.Context, path string) (string, error)
- func (c *DataplaneClient) GetMapFileContent(ctx context.Context, name string) (string, error)
- func (c *DataplaneClient) GetRawConfiguration(ctx context.Context) (string, error)
- func (c *DataplaneClient) GetReloadStatus(ctx context.Context, reloadID string) (*ReloadInfo, error)
- func (c *DataplaneClient) GetRuntimeMapEntries(ctx context.Context, name string) (map[string]string, error)
- func (c *DataplaneClient) GetSSLCaFileContent(ctx context.Context, name string) (string, error)
- func (c *DataplaneClient) GetSSLCertificateContent(ctx context.Context, name string) (string, error)
- func (c *DataplaneClient) GetVersion(ctx context.Context) (int64, error)
- func (c *DataplaneClient) PreferredClient() any
- func (c *DataplaneClient) PushRawConfiguration(ctx context.Context, config string, version int64) (string, error)
- func (c *DataplaneClient) PushRawConfigurationSkipReload(ctx context.Context, config string, version int64, runtimeActions string) error
- func (c *DataplaneClient) PushRawConfigurationSkipReloadSkipVersion(ctx context.Context, config, runtimeActions string) error
- func (c *DataplaneClient) ReplaceRuntimeMap(ctx context.Context, name, desiredContent string) error
- func (c *DataplaneClient) ReplaceRuntimeSSLCaFiles(ctx context.Context, contentByPath map[string]string) error
- func (c *DataplaneClient) ReplaceRuntimeSSLCerts(ctx context.Context, pemByName map[string]string) error
- func (c *DataplaneClient) UpdateCRTListFile(ctx context.Context, name, content string) (string, error)
- func (c *DataplaneClient) UpdateGeneralFile(ctx context.Context, path, content string) (string, error)
- func (c *DataplaneClient) UpdateMapFile(ctx context.Context, name, content string) (string, error)
- func (c *DataplaneClient) UpdateSSLCaFile(ctx context.Context, name, content string) (string, error)
- func (c *DataplaneClient) UpdateSSLCertificate(ctx context.Context, name, content string) (string, error)
- func (c *DataplaneClient) VerifyRuntimeMap(ctx context.Context, name, desiredContent string) (int, error)
- type Endpoint
- type ReloadInfo
- type ReloadStatus
- type RetryCondition
- type RetryConfig
- type Version
- type VersionInfo
Constants ¶
const ReloadIDHeader = "Reload-Id"
ReloadIDHeader is the HTTP header name used by HAProxy Data Plane API to return the reload ID when an operation triggers a reload.
Variables ¶
var ( // ErrCrtListRequiresV32 is returned when crt-list storage operations are attempted // on DataPlane API versions below v3.2. ErrCrtListRequiresV32 = errors.New("crt-list storage requires DataPlane API v3.2+") // ErrSSLCaFilesRequireV32 is returned when SSL CA file operations are attempted // on DataPlane API versions below v3.2. ErrSSLCaFilesRequireV32 = errors.New("SSL CA file storage requires DataPlane API v3.2+") )
Functions ¶
func CheckResponse ¶
CheckResponse validates an HTTP response status code and logs failures with full context. It reads and logs the response body for debugging, then returns a user-friendly error.
Usage:
resp, err := c.Dispatch(ctx, callFunc)
if err != nil {
return fmt.Errorf("creating backend: %w", err)
}
defer resp.Body.Close()
if err := client.CheckResponse(resp, "create backend"); err != nil {
return err
}
func IsEnterpriseVersion ¶
IsEnterpriseVersion returns true when the version string matches one of the known HAProxy Enterprise formats.
func SanitizeSSLCertName ¶
SanitizeSSLCertName sanitizes a certificate name for HAProxy Data Plane API storage. The API replaces dots in the filename (excluding the extension) with underscores. For example: "example.com.pem" becomes "example_com.pem". This function is exported for use in tests to compare certificate names.
func SanitizeStorageName ¶
SanitizeStorageName sanitizes a filename for HAProxy storage. The API replaces dots in the filename (excluding the extension) with underscores. Example: "example.com.pem" becomes "example_com.pem".
func UnsanitizeStorageName ¶
UnsanitizeStorageName reverses sanitization (best-effort). Converts underscores back to dots in the basename. Example: "example_com.pem" becomes "example.com.pem". Note: This may not be perfect for filenames that originally contained underscores.
func WithRetry ¶
func WithRetry[T any](ctx context.Context, config RetryConfig, fn func(attempt int) (T, error)) (T, error)
WithRetry executes fn with automatic retry logic based on config.
The function fn is called with the current attempt number (1-indexed). If fn returns an error and config.RetryIf returns true, the operation is retried up to config.MaxAttempts times.
Example:
config := RetryConfig{
MaxAttempts: 3,
RetryIf: IsVersionConflict(),
Backoff: BackoffExponential,
BaseDelay: 100 * time.Millisecond,
Logger: logger,
}
result, err := WithRetry(ctx, config, func(attempt int) (*Result, error) {
return doOperation(ctx, attempt)
})
Types ¶
type BackoffStrategy ¶
type BackoffStrategy string
BackoffStrategy determines the delay between retry attempts.
const ( // BackoffExponential applies exponentially increasing delays between retries. // It is the only strategy production uses; any other value (including the // zero value) means no delay. BackoffExponential BackoffStrategy = "exponential" )
type CallFunc ¶
type CallFunc[T any] struct { // Community edition clients // V33 is the function to call for DataPlane API v3.3+ V33 func(*v33.Client) (T, error) // V32 is the function to call for DataPlane API v3.2 V32 func(*v32.Client) (T, error) // V31 is the function to call for DataPlane API v3.1 V31 func(*v31.Client) (T, error) // V30 is the function to call for DataPlane API v3.0 V30 func(*v30.Client) (T, error) // Enterprise edition clients // V32EE is the function to call for HAProxy Enterprise DataPlane API v3.2+ V32EE func(*v32ee.Client) (T, error) // V31EE is the function to call for HAProxy Enterprise DataPlane API v3.1 V31EE func(*v31ee.Client) (T, error) // V30EE is the function to call for HAProxy Enterprise DataPlane API v3.0 V30EE func(*v30ee.Client) (T, error) }
CallFunc represents a versioned API call function. Each field is a function that takes a version-specific client and returns a result of type T. This allows type-safe dispatch to the appropriate client version based on runtime detection.
For HAProxy Community editions, use V30, V31, V32, V33. For HAProxy Enterprise editions, use V30EE, V31EE, V32EE.
Example usage:
resp, err := c.Dispatch(ctx, CallFunc[*http.Response]{
V32: func(c *v32.Client) (*http.Response, error) { return c.SomeMethod(ctx, params) },
V31: func(c *v31.Client) (*http.Response, error) { return c.SomeMethod(ctx, params) },
V30: func(c *v30.Client) (*http.Response, error) { return c.SomeMethod(ctx, params) },
V32EE: func(c *v32ee.Client) (*http.Response, error) { return c.SomeMethod(ctx, params) },
V31EE: func(c *v31ee.Client) (*http.Response, error) { return c.SomeMethod(ctx, params) },
V30EE: func(c *v30ee.Client) (*http.Response, error) { return c.SomeMethod(ctx, params) },
})
type Capabilities ¶
type Capabilities struct {
// Storage capabilities
SupportsCrtList bool // /v3/storage/ssl_crt_lists (v3.2+)
SupportsMapStorage bool // /v3/storage/maps (v3.0+)
SupportsGeneralStorage bool // /v3/storage/general (v3.0+)
SupportsSslCaFiles bool // /v3/runtime/ssl_ca_files (v3.2+)
SupportsSslCrlFiles bool // /v3/runtime/ssl_crl_files (v3.2+)
SupportsRuntimeSSLCerts bool // /v3/runtime/ssl_certs replaceCert (v3.2+)
// Configuration capabilities
SupportsHTTP2 bool // HTTP/2 configuration (v3.0+)
SupportsQUIC bool // QUIC/HTTP3 configuration (v3.0+)
SupportsQUICInitialRules bool // QUIC initial rules endpoints (v3.1+)
// Observability capabilities
SupportsLogProfiles bool // /v3/services/haproxy/configuration/log_profiles (v3.1+)
SupportsTraces bool // /v3/services/haproxy/configuration/traces (v3.1+)
// Certificate automation capabilities
SupportsAcmeProviders bool // /v3/services/haproxy/configuration/acmes (v3.2+)
// Model metadata capabilities
SupportsConfigMetadata bool // Metadata field on config models like ACL, Server, etc. (v3.2+)
// Runtime capabilities
SupportsRuntimeMaps bool // Runtime map operations (v3.0+)
SupportsRuntimeServers bool // Runtime server operations (v3.0+)
// SupportsWAF indicates WAF management endpoints are available.
// Includes: waf_body_rules (frontend/backend), waf/rulesets
// Note: waf_global and waf_profiles require v3.2+ (see SupportsWAFGlobal, SupportsWAFProfiles)
SupportsWAF bool
// SupportsWAFGlobal indicates WAF global configuration endpoint is available.
// Only available in HAProxy Enterprise v3.2+ (waf_global endpoint)
SupportsWAFGlobal bool
// SupportsWAFProfiles indicates WAF profile management endpoints are available.
// Only available in HAProxy Enterprise v3.2+ (waf_profiles endpoint)
SupportsWAFProfiles bool
// SupportsUDPLBACLs indicates UDP load balancer ACL endpoints are available.
// Only available in HAProxy Enterprise v3.2+ (udp_lbs/{name}/acls endpoint)
SupportsUDPLBACLs bool
// SupportsUDPLBServerSwitchingRules indicates UDP load balancer server switching rule endpoints are available.
// Only available in HAProxy Enterprise v3.2+ (udp_lbs/{name}/server_switching_rules endpoint)
SupportsUDPLBServerSwitchingRules bool
// SupportsKeepalived indicates Keepalived/VRRP management endpoints are available.
// Includes: vrrp_instances, vrrp_sync_groups, vrrp_track_scripts, keepalived transactions
SupportsKeepalived bool
// SupportsUDPLoadBalancing indicates UDP load balancer management endpoints are available.
// Includes: udp_lbs with ACLs, dgram_binds, log_targets, server_switching_rules
SupportsUDPLoadBalancing bool
// SupportsBotManagement indicates bot management endpoints are available.
// Includes: botmgmt_profiles, captchas
SupportsBotManagement bool
// SupportsGitIntegration indicates Git integration endpoints are available.
// Includes: git/settings, git/actions
SupportsGitIntegration bool
// SupportsDynamicUpdate indicates dynamic update endpoints are available.
// Includes: dynamic_update_rules, dynamic_update_section
SupportsDynamicUpdate bool
// SupportsALOHA indicates ALOHA feature endpoints are available.
// Includes: aloha, aloha/actions
SupportsALOHA bool
// SupportsAdvancedLogging indicates advanced logging endpoints are available.
// Includes: logs/config, logs/inputs, logs/outputs
SupportsAdvancedLogging bool
// SupportsPing indicates the ping endpoint is available.
// Only available in HAProxy Enterprise v3.2+ (/v3/ping endpoint)
SupportsPing bool
}
Capabilities defines which features are available for a given DataPlane API version. Version thresholds verified against OpenAPI specs for v3.0, v3.1, v3.2, v3.3.
type Clientset ¶
type Clientset struct {
// contains filtered or unexported fields
}
Clientset provides access to clients for all supported HAProxy DataPlane API versions. This follows the Kubernetes clientset pattern, allowing version-specific operations while maintaining compatibility across HAProxy versions.
func NewClientset ¶
NewClientset creates a new multi-version clientset for the given endpoint. It detects the server's DataPlane API version and creates appropriate clients.
Example:
// endpoint is taken by pointer so &client.Endpoint{...} is required.
clientset, err := client.NewClientset(ctx, &client.Endpoint{
URL: "http://haproxy:5555",
Username: "admin",
Password: "password",
}, logger)
if err != nil {
return err
}
// Use version-specific client. Naming the variable `versioned`
// avoids shadowing the imported `client` package.
if clientset.Capabilities().SupportsCrtList {
versioned := clientset.V32()
// Use v3.2-specific features
_ = versioned
} else {
versioned := clientset.V30()
// Fallback to v3.0-compatible operations
_ = versioned
}
func (*Clientset) Capabilities ¶
func (c *Clientset) Capabilities() Capabilities
Capabilities returns the feature availability map for the detected version.
func (*Clientset) DetectedVersion ¶
DetectedVersion returns the full version string detected from the server. Example: "v3.2.6 87ad0bcf" for community or "v3.0r1" for enterprise.
func (*Clientset) IsEnterprise ¶
IsEnterprise returns true if the detected HAProxy is an Enterprise edition.
func (*Clientset) MajorVersion ¶
MajorVersion returns the major version number (e.g., 3 for v3.x).
func (*Clientset) MinorVersion ¶
MinorVersion returns the minor version number (e.g., 0, 1, or 2 for v3.0, v3.1, v3.2).
func (*Clientset) PreferredClient ¶
PreferredClient returns the most appropriate client based on detected version and edition. This is useful for code that wants to use the best available API without explicitly checking capabilities.
Returns:
- Enterprise clients (v32ee, v31ee, v30ee) if HAProxy Enterprise is detected
- Community clients (v32, v31, v30) for HAProxy Community
Version selection (newer minors clamp down to the newest bundled client):
- v3.3 client if server is v3.3 or newer
- v3.2 client if server is v3.2
- v3.1 client if server is v3.1
- v3.0 client if server is v3.0 or unknown
func (*Clientset) V30 ¶
V30 returns the DataPlane API v3.0 client. This client is compatible with HAProxy 2.4 and later.
func (*Clientset) V31 ¶
V31 returns the DataPlane API v3.1 client. This client is compatible with HAProxy 2.6 and later.
func (*Clientset) V32 ¶
V32 returns the DataPlane API v3.2 client. This client is compatible with HAProxy 2.8 and later.
type Config ¶
type Config struct {
// BaseURL is the HAProxy Dataplane API endpoint (e.g., "http://localhost:5555/v3").
// A trailing "/v2" or "/v3" is stripped before the v3 version-detection probe;
// only v3.x operations are supported (no v2-only endpoints).
BaseURL string
// Username for basic authentication
Username string
// Password for basic authentication
Password string
// PodName is the Kubernetes pod name (for observability)
PodName string
// HTTPClient allows injecting a custom HTTP client (useful for testing)
HTTPClient *http.Client
// Logger for logging request/response details on errors (optional)
// If nil, slog.Default() will be used
Logger *slog.Logger
}
Config contains configuration options for creating a DataplaneClient.
type DataplaneClient ¶
type DataplaneClient struct {
Endpoint Endpoint // Embedded endpoint information
// contains filtered or unexported fields
}
DataplaneClient wraps the multi-version Clientset with additional functionality for HAProxy Dataplane API operations. It automatically uses the appropriate client version based on runtime detection.
func New ¶
func New(ctx context.Context, cfg *Config) (*DataplaneClient, error)
New creates a new DataplaneClient with the provided configuration. It automatically detects the server's DataPlane API version and creates an appropriate multi-version clientset.
Example:
// dpClient avoids shadowing the imported `client` package; cfg is
// taken by pointer so &client.Config{...} is required.
dpClient, err := client.New(ctx, &client.Config{
BaseURL: "http://haproxy-dataplane:5555",
Username: "admin",
Password: "password",
})
func NewFromEndpoint ¶
func NewFromEndpoint(ctx context.Context, endpoint *Endpoint, logger *slog.Logger) (*DataplaneClient, error)
NewFromEndpoint creates a new DataplaneClient from an Endpoint. This is a convenience function for creating a client with default options.
func (*DataplaneClient) AddRuntimeCaFileEntry ¶
func (c *DataplaneClient) AddRuntimeCaFileEntry(ctx context.Context, name, content string) error
AddRuntimeCaFileEntry replaces the live (in-memory) contents of an existing, config-referenced CA file via the runtime add-entry endpoint (`add ssl ca-file` + `commit ssl ca-file`), WITHOUT a reload. With no ongoing transaction, `add ssl ca-file` starts an EMPTY transaction and commit replaces the file with the payload — so passing the full desired bundle replaces the live CA file (verified: a 2-cert bundle replaces a 1-cert file, no reload). v3.2+ only.
HAPTIC uses this instead of UpdateSSLCaFile (set ssl ca-file): the DataPlane API's `set ssl ca-file` runtime path returns 500 under the master-worker `set severity-output number;@1 <heredoc>;quit` wrapping — the slower CA validation races the connection close and its response is lost. `add ssl ca-file` wins that race and applies reliably. (Upstream client-native quirk; see the runtime-socket reduction audit memo.)
func (*DataplaneClient) BaseURL ¶
func (c *DataplaneClient) BaseURL() string
BaseURL returns the configured base URL for the Dataplane API.
func (*DataplaneClient) Capabilities ¶
func (c *DataplaneClient) Capabilities() Capabilities
Capabilities returns the feature availability for the detected version.
func (*DataplaneClient) Clientset ¶
func (c *DataplaneClient) Clientset() *Clientset
Clientset returns the underlying multi-version clientset for advanced operations. Use this when you need version-specific features or capability checking.
Example:
if client.Clientset().Capabilities().SupportsCrtList {
v32Client := client.Clientset().V32()
// Use v3.2-specific crt-list operations
}
func (*DataplaneClient) CreateCRTListFile ¶
func (c *DataplaneClient) CreateCRTListFile(ctx context.Context, name, content string) (string, error)
CreateCRTListFile creates a new crt-list file using multipart form-data. Returns the reload ID if a reload was triggered (empty string if not) and any error. The name parameter can use dots (e.g., "example.com.crtlist"), which will be sanitized automatically before calling the API. CRT-list storage is only available in HAProxy DataPlane API v3.2+.
func (*DataplaneClient) CreateGeneralFile ¶
func (c *DataplaneClient) CreateGeneralFile(ctx context.Context, path, content string) (string, error)
CreateGeneralFile creates a new general file using multipart form-data. Returns the reload ID if a reload was triggered (empty string if not) and any error. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) CreateMapFile ¶
CreateMapFile creates a new map file using multipart form-data. Returns the reload ID if a reload was triggered (empty string if not) and any error. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) CreateSSLCaFile ¶
func (c *DataplaneClient) CreateSSLCaFile(ctx context.Context, name, content string) (string, error)
CreateSSLCaFile creates a new SSL CA file using multipart form-data. Returns the reload ID if a reload was triggered (empty string if not) and any error. SSL CA file storage is only available in HAProxy DataPlane API v3.2+.
func (*DataplaneClient) CreateSSLCertificate ¶
func (c *DataplaneClient) CreateSSLCertificate(ctx context.Context, name, content string) (string, error)
CreateSSLCertificate creates a new SSL certificate using multipart form-data, always sending skip_reload=true. Symmetric with UpdateSSLCertificate's existing skip_reload plumbing (added in 77c760c2 "skip_reload=true on aux-file UPDATEs"); the asymmetry on CREATE was an oversight, since the DPAPI's POST /storage/ssl_certificates endpoint declares skip_reload as a query parameter (unlike POST /storage/maps and /storage/general, where the spec doesn't expose it).
Without this, every cert CREATE during PhasePreConfig triggers a DPAPI auto-reload that validates the CURRENT haproxy.cfg against the new on-disk cert. The reload normally succeeds (the new cert is just-written real content), but a parallel reconciliation cycle landing between the cert CREATE's reload and the orchestrator's PhaseConfig push can race against stale-cfg state — same shape as the UPDATE bug the May fix closed.
Returns the reload ID if a reload was triggered (always empty under skip_reload=true) and any error. The name parameter can use dots (e.g., "example.com.pem"), which will be sanitized automatically before calling the API. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) DeleteCRTListFile ¶
func (c *DataplaneClient) DeleteCRTListFile(ctx context.Context, name string) error
DeleteCRTListFile deletes a crt-list file by name, always sending skip_reload=true — without it, the DPAPI schedules its own uncoordinated reload (see DeleteSSLCertificate for the full rationale; deletion only runs for files the live config no longer references, so no reload is needed to apply it). The name parameter can use dots (e.g., "example.com.crtlist"), which will be sanitized automatically before calling the API. CRT-list storage is only available in HAProxy DataPlane API v3.2+.
func (*DataplaneClient) DeleteGeneralFile ¶
func (c *DataplaneClient) DeleteGeneralFile(ctx context.Context, path string) error
DeleteGeneralFile deletes a general file by path. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) DeleteMapFile ¶
func (c *DataplaneClient) DeleteMapFile(ctx context.Context, name string) error
DeleteMapFile deletes a map file by name. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) DeleteSSLCaFile ¶
func (c *DataplaneClient) DeleteSSLCaFile(ctx context.Context, name string) error
DeleteSSLCaFile deletes an SSL CA file by name. SSL CA file storage is only available in HAProxy DataPlane API v3.2+.
func (*DataplaneClient) DeleteSSLCertificate ¶
func (c *DataplaneClient) DeleteSSLCertificate(ctx context.Context, name string) error
DeleteSSLCertificate deletes an SSL certificate by name, always sending skip_reload=true. This closes the last gap in the skip_reload family (UPDATE got it in 77c760c2, CREATE followed): without it, the DPAPI answers 202 and its reload agent schedules a SECOND, uncoordinated reload shortly after the deploy's own force_reload config push (deletes run post-config, so the deleted cert is already unreferenced by the live config and running workers keep their in-memory copy — nothing needs a reload). That stray reload blacks out the master CLI socket mid-rollout, which is exactly the window issue #67 captured: endpoint fast-path `set server` pushes fail against the re-executing master while the outgoing worker drains with a stale server list, turning a routine single-replica rollout into a 503.
The name parameter can use dots (e.g., "example.com.pem"), which will be sanitized automatically before calling the API. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) DetectedVersion ¶
func (c *DataplaneClient) DetectedVersion() string
DetectedVersion returns the full version string of the DataPlane API server.
func (*DataplaneClient) Dispatch ¶
func (c *DataplaneClient) Dispatch(ctx context.Context, call CallFunc[*http.Response]) (*http.Response, error)
Dispatch executes the appropriate versioned function based on the detected API version. This is the primary method for executing API calls that work across all versions.
Returns error if:
- The client type is unexpected
- The version-specific function is nil
- The versioned function itself returns an error
Example:
resp, err := c.Dispatch(ctx, CallFunc[*http.Response]{
V32: func(c *v32.Client) (*http.Response, error) {
return c.GetAllStorageMapFiles(ctx)
},
V31: func(c *v31.Client) (*http.Response, error) {
return c.GetAllStorageMapFiles(ctx)
},
V30: func(c *v30.Client) (*http.Response, error) {
return c.GetAllStorageMapFiles(ctx)
},
})
func (*DataplaneClient) DispatchWithCapability ¶
func (c *DataplaneClient) DispatchWithCapability( ctx context.Context, call CallFunc[*http.Response], capabilityCheck func(Capabilities) error, ) (*http.Response, error)
DispatchWithCapability executes the appropriate versioned function with an optional capability check. Use this for version-specific features (e.g., crt-list only available in v3.2+).
The capability check is performed before executing the versioned function. If the check fails, the function is not executed and the capability error is returned.
Parameters:
- ctx: Context for the API call
- call: Version-specific functions to execute
- capabilityCheck: Optional function to verify feature availability. If nil, no check is performed.
Returns error if:
- Capability check fails
- The client type is unexpected
- The version-specific function is nil
- The versioned function itself returns an error
Example (CRT-list only in v3.2+):
resp, err := c.DispatchWithCapability(ctx, CallFunc[*http.Response]{
V32: func(c *v32.Client) (*http.Response, error) {
return c.GetAllStorageSSLCrtListFiles(ctx)
},
// V31 and V30 omitted - not supported
}, func(caps Capabilities) error {
if !caps.SupportsCrtList {
return errors.New("crt-list storage requires DataPlane API v3.2+")
}
return nil
})
func (*DataplaneClient) GetAllCRTListFiles ¶
func (c *DataplaneClient) GetAllCRTListFiles(ctx context.Context) ([]string, error)
GetAllCRTListFiles retrieves all crt-list file names from the storage. Note: This returns only crt-list file names, not the file contents. Use GetCRTListFileContent to retrieve the actual file contents. CRT-list storage is only available in HAProxy DataPlane API v3.2+.
func (*DataplaneClient) GetAllGeneralFiles ¶
func (c *DataplaneClient) GetAllGeneralFiles(ctx context.Context) ([]string, error)
GetAllGeneralFiles retrieves all general file paths from the storage. Note: This returns only file paths, not the file contents. Use GetGeneralFileContent to retrieve the actual file contents. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) GetAllMapFiles ¶
func (c *DataplaneClient) GetAllMapFiles(ctx context.Context) ([]string, error)
GetAllMapFiles retrieves all map file names from the storage. Note: This returns only map file names, not the file contents. Use GetMapFileContent to retrieve the actual file contents. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) GetAllSSLCaFiles ¶
func (c *DataplaneClient) GetAllSSLCaFiles(ctx context.Context) ([]string, error)
GetAllSSLCaFiles retrieves all SSL CA file names from the runtime storage. Note: This returns only CA file names, not the file contents. Use GetSSLCaFileContent to retrieve the actual file contents. SSL CA file storage is only available in HAProxy DataPlane API v3.2+.
func (*DataplaneClient) GetAllSSLCertificates ¶
func (c *DataplaneClient) GetAllSSLCertificates(ctx context.Context) ([]string, error)
GetAllSSLCertificates retrieves all SSL certificate names from the storage. Note: This returns only certificate names, not the certificate contents. Use GetSSLCertificateContent to retrieve the actual certificate contents. The returned names are unsanitized (dots restored) for user convenience. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) GetCRTListFileContent ¶
GetCRTListFileContent retrieves the content of a specific crt-list file by name. The name parameter can use dots (e.g., "example.com.crtlist"), which will be sanitized automatically before calling the API. CRT-list storage is only available in HAProxy DataPlane API v3.2+.
func (*DataplaneClient) GetGeneralFileContent ¶
GetGeneralFileContent retrieves the content of a specific general file by path. The API returns the raw file content as application/octet-stream. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) GetMapFileContent ¶
GetMapFileContent retrieves the content of a specific map file by name. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) GetRawConfiguration ¶
func (c *DataplaneClient) GetRawConfiguration(ctx context.Context) (string, error)
GetRawConfiguration retrieves the current HAProxy configuration as a string.
This fetches the raw configuration file content from the Dataplane API. The configuration can be parsed using the parser package to get structured data. Works with all HAProxy DataPlane API versions (v3.0+).
Example:
config, err := dpClient.GetRawConfiguration(context.Background())
if err != nil {
slog.Error("Failed to get config", "error", err)
os.Exit(1)
}
fmt.Printf("Current config:\n%s\n", config)
func (*DataplaneClient) GetReloadStatus ¶
func (c *DataplaneClient) GetReloadStatus(ctx context.Context, reloadID string) (*ReloadInfo, error)
GetReloadStatus retrieves the status of a specific HAProxy reload operation.
This method polls the DataPlane API to check if an async reload has completed. Use this after receiving a 202 response from configuration changes to verify the reload succeeded. Works with all HAProxy DataPlane API versions (v3.0+).
Parameters:
- reloadID: The reload identifier from the Reload-ID header
Returns:
- ReloadInfo: Current status and details of the reload
- error: Error if the API call fails or reload ID not found
Example:
info, err := dpClient.GetReloadStatus(ctx, "abc123")
if err != nil {
log.Fatal(err)
}
switch info.Status {
case ReloadStatusSucceeded:
log.Println("Reload completed successfully")
case ReloadStatusFailed:
log.Printf("Reload failed: %s", info.Response)
case ReloadStatusInProgress:
log.Println("Reload still in progress")
}
func (*DataplaneClient) GetRuntimeMapEntries ¶
func (c *DataplaneClient) GetRuntimeMapEntries(ctx context.Context, name string) (map[string]string, error)
GetRuntimeMapEntries returns the live (in-memory) entries of a runtime map as a key→value map (last value wins on duplicate keys). Exposed for tests that need to assert the worker's in-memory map state, not just the on-disk file.
func (*DataplaneClient) GetSSLCaFileContent ¶
GetSSLCaFileContent retrieves the content of a specific SSL CA file by name. SSL CA file storage is only available in HAProxy DataPlane API v3.2+.
func (*DataplaneClient) GetSSLCertificateContent ¶
func (c *DataplaneClient) GetSSLCertificateContent(ctx context.Context, name string) (string, error)
GetSSLCertificateContent retrieves the SHA256 fingerprint for a specific SSL certificate by name.
This function returns the sha256_finger_print field from the HAProxy Data Plane API, which serves as a unique identifier for the certificate content. This allows content-based comparison without needing to download the actual PEM data.
The API provides rich metadata including:
- sha256_finger_print: SHA-256 hash of certificate content (returned by this function)
- serial: Certificate serial number
- issuers: Certificate issuer information
- subject: Certificate subject information
- not_after, not_before: Certificate validity period
The name parameter can use dots (e.g., "example.com.pem"), which will be sanitized automatically before calling the API.
Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) GetVersion ¶
func (c *DataplaneClient) GetVersion(ctx context.Context) (int64, error)
GetVersion retrieves the current configuration version from the Dataplane API.
The version is used for optimistic locking when making configuration changes. This prevents concurrent modifications from conflicting. Works with all HAProxy DataPlane API versions (v3.0+).
Example:
version, err := dpClient.GetVersion(context.Background())
if err != nil {
slog.Error("Failed to get version", "error", err)
os.Exit(1)
}
fmt.Printf("Current version: %d\n", version)
func (*DataplaneClient) PreferredClient ¶
func (c *DataplaneClient) PreferredClient() any
PreferredClient returns the most appropriate versioned client based on the detected server version. Returns one of: *v30.Client, *v31.Client, *v32.Client.
For most operations, you should use the wrapper methods instead of this. This is provided for operations that aren't wrapped yet.
func (*DataplaneClient) PushRawConfiguration ¶
func (c *DataplaneClient) PushRawConfiguration(ctx context.Context, config string, version int64) (string, error)
PushRawConfiguration pushes a new HAProxy configuration to the Dataplane API.
This triggers a full HAProxy reload and is the production apply path for structural changes (anything outside the runtime-eligible server-field set). When every change is runtime-eligible, prefer PushRawConfigurationSkipReload, which writes the new config to disk and applies the server changes to the running worker without a reload. Works with all HAProxy DataPlane API versions (v3.0+).
Parameters:
- config: The complete HAProxy configuration string
- version: The expected configuration version for optimistic locking. The version is incremented after a successful push.
Returns:
- reloadID: The reload identifier from the Reload-ID header (if reload triggered)
- error: Error if the push fails
Example:
reloadID, err := dpClient.PushRawConfiguration(context.Background(), newConfig, 1)
if err != nil {
slog.Error("Failed to push config", "error", err)
os.Exit(1)
}
if reloadID != "" {
slog.Info("HAProxy reloaded", "reload_id", reloadID)
}
func (*DataplaneClient) PushRawConfigurationSkipReload ¶
func (c *DataplaneClient) PushRawConfigurationSkipReload(ctx context.Context, config string, version int64, runtimeActions string) error
PushRawConfigurationSkipReload pushes the full config to disk without triggering a reload. The runtimeActions string is a semicolon-separated list of runtime socket commands that HAProxy applies immediately via stats socket after the config file is written. (e.g., "SetServerAddr backend srv 10.0.0.1 8080;SetServerState backend srv ready"). This allows N server state changes to be applied atomically in a single API call, replacing N serial ReplaceServerBackend calls that each re-read haproxy.cfg from disk.
func (*DataplaneClient) PushRawConfigurationSkipReloadSkipVersion ¶
func (c *DataplaneClient) PushRawConfigurationSkipReloadSkipVersion(ctx context.Context, config, runtimeActions string) error
PushRawConfigurationSkipReloadSkipVersion is the queue-bypass variant of PushRawConfigurationSkipReload: it applies the runtime actions without a reload AND without the optimistic-locking version check (skip_version).
The deployer's runtime bypass fires this immediately when a queued reconcile produces runtime-eligible server changes, OUTSIDE the deployment scheduler's serialization — so a pod-IP rotation reaches the live worker in ~ms instead of waiting in the pending slot behind an in-flight ~200ms structural reload. The caller passes the CURRENT on-disk config as the body (so a co-batched reconcile's structural changes are NOT written to disk without a reload); only the runtime actions take effect on the live worker.
NB: skip_version does NOT bump the config version — the dataplane writes the pushed body VERBATIM, without the `# _version=N` header and without incrementing anything (client-native raw.go writes the header only on the versioned path; transaction.go skips IncrementTransactionVersion when skipVersion is set). After this push GetVersion reads the missing header as 1, the headerless sentinel. The orchestrator therefore treats version 1 as uncacheable and never satisfies a version-cache check with it (see headerlessConfigVersion in pkg/dataplane), so the next versioned sync always re-fetches the pod's actual config and re-stamps the header. The runtime change persists across the scheduled deploy's structural reload because that deploy re-renders the current endpoints (config-driven; no server-state-file — ADR-0011).
func (*DataplaneClient) ReplaceRuntimeMap ¶
func (c *DataplaneClient) ReplaceRuntimeMap(ctx context.Context, name, desiredContent string) error
ReplaceRuntimeMap makes the live (in-memory) contents of an existing runtime map equal the entries parsed from desiredContent, by applying the minimal per-entry delta (add/delete) against the current runtime state. It applies WITHOUT a reload and is available on all DataPlane API versions (v3.0+).
It deliberately does NOT use a bulk "add payload" (which appends rather than replaces, leaving stale and duplicate entries) nor a clear+repopulate (which would briefly empty the whole map). A changed single-value key is updated in-place with `set map` (atomic, no gap); only multi-value keys and removals use del(+add). Unchanged keys are untouched, so the map is always valid.
force_sync is intentionally NOT set: the orchestrator's pre-config phase already wrote the desired content to the on-disk map file (skip_reload), so disk durability (reload convergence) is handled there. This call only updates the live worker's memory, and must not push memory back to disk.
name is the map's identifier as HAProxy reports it (the path used in the config); the map must already exist and be referenced by the running config.
func (*DataplaneClient) ReplaceRuntimeSSLCaFiles ¶
func (c *DataplaneClient) ReplaceRuntimeSSLCaFiles(ctx context.Context, contentByPath map[string]string) error
ReplaceRuntimeSSLCaFiles replaces the live (in-memory) contents of one or more already-loaded SSL CA files (mTLS trust bundles) on the worker via the runtime API (`add ssl ca-file` + `commit ssl ca-file`, which replaces the file with the payload — see AddRuntimeCaFileEntry for why `add` is used instead of `set`), WITHOUT a reload. contentByPath maps each ca-file's config path (the `ca-file <path>` argument HAProxy loaded) to its new bundle. Available on DataPlane API v3.2+ only — callers must gate on Capabilities().SupportsSslCaFiles.
The loaded-ca-file list is fetched ONCE and reused to resolve every file's runtime identifier, so N rotations cost a single list fetch. Like ReplaceRuntimeMap / ReplaceRuntimeSSLCerts, disk durability is left to the orchestrator's pre-config general-storage write (skip_reload); this call only updates the live worker's memory.
This is the controller-side equivalent of what the SPIFFE cert-reloader sidecar does over the raw stats socket (`set ssl ca-file <bundle>`), routed through the DataPlane API instead.
func (*DataplaneClient) ReplaceRuntimeSSLCerts ¶
func (c *DataplaneClient) ReplaceRuntimeSSLCerts(ctx context.Context, pemByName map[string]string) error
ReplaceRuntimeSSLCerts replaces the live (in-memory) contents of one or more already-loaded SSL certificates on the worker via the runtime API (set ssl cert + commit ssl cert, applied atomically per cert by the DataPlane API), WITHOUT a reload. pemByName maps each cert's config identifier to its new PEM. Available on DataPlane API v3.2+ only — callers must gate on Capabilities().SupportsRuntimeSSLCerts; older versions take the reload path.
The loaded-cert list is fetched ONCE and reused to resolve every cert's runtime identifier, so N rotations cost a single list fetch, not N.
Like ReplaceRuntimeMap, disk durability is left to the orchestrator's pre-config storage write (skip_reload); this updates worker memory only and carries no force_sync.
func (*DataplaneClient) UpdateCRTListFile ¶
func (c *DataplaneClient) UpdateCRTListFile(ctx context.Context, name, content string) (string, error)
UpdateCRTListFile updates an existing crt-list file using text/plain content-type, always sending skip_reload=true (see DeleteSSLCertificate for the rationale — the deploy pipeline's config push is the only coordinated reload trigger). Returns the reload ID if a reload was triggered (always empty under skip_reload=true) and any error. Note: The Dataplane API requires text/plain or application/json for UPDATE operations, while CREATE operations accept multipart/form-data. The CREATE endpoint declares no skip_reload parameter at all, which is why production crt-lists are stored as general files instead (see paths.go). The name parameter can use dots (e.g., "example.com.crtlist"), which will be sanitized automatically before calling the API. CRT-list storage is only available in HAProxy DataPlane API v3.2+.
func (*DataplaneClient) UpdateGeneralFile ¶
func (c *DataplaneClient) UpdateGeneralFile(ctx context.Context, path, content string) (string, error)
UpdateGeneralFile updates an existing general file using multipart form-data. Always sends skip_reload=true so the dataplane API does NOT auto-reload after the PUT. The new content is written to disk; HAProxy keeps using the in-memory copy until the next reload. This matches Create's 201-with-no-reload behavior and lets the orchestrator batch every aux-file change into the single reload that the main config sync triggers (or, when only aux files changed, the explicit force-reload at the end of the config sync).
The previous behavior (default reload after PUT) caused an auxiliary-reload race on route deletion: the new spoe.conf could land before the new haproxy.cfg, and the auto-reload would fire against the stale haproxy.cfg whose `send-spoe-group <name>` references no longer resolved.
Returns the reload ID if a reload was triggered (always empty under skip_reload=true) and any error. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) UpdateMapFile ¶
UpdateMapFile updates an existing map file using text/plain content-type. Always sends skip_reload=true; see UpdateGeneralFile for the rationale (auto-reload after PUT raced against stale haproxy.cfg on shrinking aux content). Returns the reload ID if a reload was triggered (always empty under skip_reload=true) and any error. Note: The Dataplane API requires text/plain or application/json for UPDATE operations, while CREATE operations accept multipart/form-data. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) UpdateSSLCaFile ¶
func (c *DataplaneClient) UpdateSSLCaFile(ctx context.Context, name, content string) (string, error)
UpdateSSLCaFile updates an existing SSL CA file using multipart form-data. Returns the reload ID if a reload was triggered (empty string if not) and any error. SSL CA file storage is only available in HAProxy DataPlane API v3.2+.
func (*DataplaneClient) UpdateSSLCertificate ¶
func (c *DataplaneClient) UpdateSSLCertificate(ctx context.Context, name, content string) (string, error)
UpdateSSLCertificate updates an existing SSL certificate using text/plain content. Always sends skip_reload=true; see UpdateGeneralFile for the rationale. The new PEM is written to disk but HAProxy keeps serving the old cert in memory until the next reload, which the orchestrator triggers explicitly when only aux files changed (and the main config sync's commit triggers it otherwise). Returns the reload ID if a reload was triggered (always empty under skip_reload=true) and any error. The name parameter can use dots (e.g., "example.com.pem"), which will be sanitized automatically before calling the API. Works with all HAProxy DataPlane API versions (v3.0+).
func (*DataplaneClient) VerifyRuntimeMap ¶
func (c *DataplaneClient) VerifyRuntimeMap(ctx context.Context, name, desiredContent string) (int, error)
VerifyRuntimeMap re-reads the live runtime map and reports how many per-entry mutations would still be needed to make it match desiredContent (0 = converged). The orchestrator's pure-runtime lane calls this right after ReplaceRuntimeMap as a read-back check: runtime map mutations are acknowledged by the Dataplane API even when the underlying master-socket command was lost in flight (observed on the haproxytech 3.1 image under reload churn — issue #48), and without a read-back the divergence latches — the on-disk file already matches desired, so no later deploy re-runs ReplaceRuntimeMap for the map and only an unrelated reload heals it.
type Endpoint ¶
type Endpoint struct {
URL string
Username string
Password string
PodName string // Kubernetes pod name for observability
// Cached version info (optional, avoids redundant /v3/info calls if set)
CachedMajorVersion int
CachedMinorVersion int
CachedFullVersion string
CachedIsEnterprise bool // True if this is HAProxy Enterprise edition
}
Endpoint represents HAProxy Dataplane API connection information. This is a convenience type alias to avoid circular imports.
func (*Endpoint) HasCachedVersion ¶
HasCachedVersion returns true if version info has been cached.
type ReloadInfo ¶
type ReloadInfo struct {
// ID is the unique identifier for this reload operation.
ID string
// Status is the current status of the reload.
Status ReloadStatus
// Response contains error details if the reload failed.
Response string
// ReloadTimestamp is the Unix timestamp when the reload occurred.
ReloadTimestamp int64
}
ReloadInfo contains information about a HAProxy reload operation.
type ReloadStatus ¶
type ReloadStatus string
ReloadStatus represents the status of a HAProxy reload operation.
const ( // ReloadStatusInProgress indicates the reload is still being processed. ReloadStatusInProgress ReloadStatus = "in_progress" // ReloadStatusSucceeded indicates the reload completed successfully. ReloadStatusSucceeded ReloadStatus = "succeeded" // ReloadStatusFailed indicates the reload failed (HAProxy reverted to previous config). ReloadStatusFailed ReloadStatus = "failed" )
type RetryCondition ¶
RetryCondition determines whether an error should trigger a retry.
func IsConnectionError ¶
func IsConnectionError() RetryCondition
IsConnectionError returns a RetryCondition that retries on transient connection errors.
This condition detects network-level connection failures such as:
- Connection refused (ECONNREFUSED) - server not yet accepting connections
- Connection reset (ECONNRESET) - connection lost during communication
These errors are typically transient and resolve within a few seconds as services start up or network conditions stabilize.
This condition does NOT retry on:
- HTTP errors (4xx, 5xx status codes)
- Authentication failures
- Parsing errors
- Context cancellation
Example:
retryConfig := RetryConfig{
MaxAttempts: 3,
RetryIf: IsConnectionError(),
Backoff: BackoffExponential,
BaseDelay: 100 * time.Millisecond,
}
result, err := WithRetry(ctx, retryConfig, func(attempt int) (*Result, error) {
return fetchFromAPI(ctx)
})
func IsReloadInProgress ¶
func IsReloadInProgress() RetryCondition
IsReloadInProgress returns a RetryCondition that retries a runtime apply that failed because HAProxy was mid-reload. While the dataplaneapi drives a reload its master socket is briefly unavailable, so runtime commands fail transiently with signatures like:
- "cannot execute SetServerState: ... haproxy-master.sock: connect: connection refused"
- "runtime server '<be>/<srv>' not found" (the runtime view is reloading)
A reload completes in tens-to-low-hundreds of ms, so a short bounded retry lets the runtime change land right after it — instead of leaving the new slot unset until the next reconcile, which is the rolling-restart gap that produced 503s under parallel-test reload churn. Version conflicts (409) and other genuine 4xx do NOT match these markers, so they fall through to the caller unchanged.
type RetryConfig ¶
type RetryConfig struct {
// MaxAttempts is the maximum number of attempts (including the first one).
// Must be >= 1. Default: 1 (no retries).
MaxAttempts int
// RetryIf determines whether to retry based on the error.
// If nil, no retries are performed.
RetryIf RetryCondition
// Backoff strategy for delays between retries.
// Default: zero value (no delay between retries).
Backoff BackoffStrategy
// BaseDelay is the initial delay for BackoffExponential (doubles each retry).
// Default: 100ms
BaseDelay time.Duration
// Logger for retry attempts. If nil, no logging is performed.
Logger *slog.Logger
}
RetryConfig configures retry behavior for operations.
type Version ¶
type Version struct {
Major int
Minor int
Patch int
Full string // Original version string, retained for logging
}
Version represents a DataPlane API / HAProxy version (major.minor.patch). Patch is best-effort: it is 0 when the source string carries only "major.minor" or a non-numeric patch segment.
This is the single version type for the project; pkg/dataplane aliases it as dataplane.Version.
func ParseVersion ¶
ParseVersion parses a DataPlane API / HAProxy version string into a Version. Examples: "v3.2.6 87ad0bcf" -> {3, 2, 6}, "3.3" -> {3, 3, 0}.
func (*Version) Compare ¶
Compare orders two versions by major, then minor. Patch is INTENTIONALLY ignored: Compare is used for series compatibility between two versions on the SAME axis — e.g. the testrunner gating a test on minHAProxyVersion, comparing two HAProxy binary versions that share major.minor but never patch. Do NOT use it to compare a DataPlane API version against a HAProxy binary version: as of HAProxy 3.4 those decouple at the minor level (the 3.4 image ships DataPlane API v3.3), so only their major versions are comparable. Returns -1 if v < other, 0 if same series, 1 if v > other.
type VersionInfo ¶
type VersionInfo struct {
API struct {
Version string `json:"version"` // e.g., "v3.2.6 87ad0bcf"
} `json:"api"`
}
VersionInfo contains detected version information from /v3/info endpoint.
func DetectVersion ¶
DetectVersion queries the /v3/info endpoint to identify the DataPlane API version advertised by the given endpoint. Callers should inspect the result with ParseVersion and IsEnterpriseVersion before deriving Capabilities.