auxiliaryfiles

package
v0.2.0-alpha.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 5, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

README

pkg/dataplane/auxiliaryfiles

Compare-and-sync helpers for the auxiliary files HAProxy serves alongside its main config: maps, general files, CRT lists, SSL certificates, and SSL CA files.

Overview

Each file kind has a Compare* and a Sync* pair. Compare fetches the current contents from the Dataplane API's storage endpoints, diffs them against a desired list, and returns a typed *FileDiffGeneric[T]. Sync applies the diff (creates / updates / deletes). The two halves can be called separately so the orchestrator can decide whether and when to commit changes.

The package only deals with auxiliary files. The main HAProxy config goes through pkg/dataplane.Client.Sync + the comparator pipeline; storage state on individual HAProxy pods (which file is on which pod) lives in pkg/k8s/configpublisher.

File Kinds and Entry Points

Kind Type Compare Sync
Maps MapFile CompareMapFiles SyncMapFiles
General files GeneralFile CompareGeneralFiles SyncGeneralFiles
SSL certificates SSLCertificate CompareSSLCertificates SyncSSLCertificates
CRT lists CRTListFile CompareCRTLists SyncCRTLists
SSL CA files SSLCaFile CompareSSLCaFiles SyncSSLCaFiles

All Compare functions return *FileDiffGeneric[T] (with type aliases FileDiff, MapFileDiff, SSLCertificateDiff, CRTListDiff, SSLCaFileDiff so call sites read naturally).

Quick Start

import (
    "gitlab.com/haproxy-haptic/haptic/pkg/dataplane/auxiliaryfiles"
    "gitlab.com/haproxy-haptic/haptic/pkg/dataplane/client"
)

dpClient, _ := client.New(ctx, &client.Config{...})

diff, err := auxiliaryfiles.CompareGeneralFiles(ctx, dpClient, desired)
if err != nil { /* ... */ }

changed, err := auxiliaryfiles.SyncGeneralFiles(ctx, dpClient, diff)
// 'changed' is the list of file names that were actually written or removed.

CRT lists are special-cased — but not for the reason an older draft of this README claimed. CompareCRTLists / SyncCRTLists always go through general-file storage via CRTListsToGeneralFiles, regardless of HAProxy version. The reason is reload accounting: the native CRT-list API (POST ssl_crt_lists) triggers a reload and doesn't support skip_reload, while general-file CREATE returns 201 with no reload, letting the orchestrator batch every aux-file change into the single reload that the main config sync triggers. There's no Capabilities.SupportsCrtList branch here. (See the Storage strategy block in crtlist.go for the rationale.)

See Also

License

Apache-2.0 — see root LICENSE.

Documentation

Overview

Package auxiliaryfiles provides functionality for synchronizing auxiliary files (general files, SSL certificates, map files, crt-lists) with the HAProxy Dataplane API.

Auxiliary files are supplementary files that HAProxy needs but are not part of the main configuration file, such as:

  • General files: Error pages, custom response files, ACL files
  • SSL certificates: TLS/SSL certificate and key files
  • Map files: Dynamic key-value mappings
  • CRT-list files: SSL certificate lists with per-certificate options

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Sync

func Sync[T FileItem](
	ctx context.Context,
	ops FileOperations[T],
	diff *FileDiffGeneric[T],
) ([]string, error)

Sync synchronizes files to the desired state by applying the provided diff.

This function should be called in two phases:

  • Phase 1 (pre-config): Call with diff containing ToCreate and ToUpdate
  • Phase 2 (post-config): Call with diff containing ToDelete

The caller is responsible for splitting the diff into these phases.

Type Parameters:

  • T: The file item type (must implement FileItem interface)

Parameters:

  • ctx: Context for cancellation
  • ops: File operations adapter for the specific file type
  • diff: The diff to apply (may contain create, update, and/or delete operations)

Returns:

  • []string: Reload IDs from create/update operations that triggered reloads
  • error: Any error encountered during synchronization

func SyncGeneralFiles

func SyncGeneralFiles(ctx context.Context, c *client.DataplaneClient, diff *FileDiff) ([]string, error)

SyncGeneralFiles synchronizes general files to the desired state by applying the provided diff. This function should be called in two phases:

  • Phase 1 (pre-config): Call with diff containing ToCreate and ToUpdate
  • Phase 2 (post-config): Call with diff containing ToDelete

The caller is responsible for splitting the diff into these phases. Returns reload IDs from create/update operations that triggered reloads.

func SyncMapFiles

func SyncMapFiles(ctx context.Context, c *client.DataplaneClient, diff *MapFileDiff) ([]string, error)

SyncMapFiles synchronizes map files to the desired state by applying the provided diff. This function should be called in two phases:

  • Phase 1 (pre-config): Call with diff containing ToCreate and ToUpdate
  • Phase 2 (post-config): Call with diff containing ToDelete

The caller is responsible for splitting the diff into these phases. Returns reload IDs from create/update operations that triggered reloads.

func SyncSSLCaFiles

func SyncSSLCaFiles(ctx context.Context, c *client.DataplaneClient, diff *SSLCaFileDiff) ([]string, error)

SyncSSLCaFiles synchronizes SSL CA files to the desired state by applying the provided diff. This function should be called in two phases:

  • Phase 1 (pre-config): Call with diff containing ToCreate and ToUpdate
  • Phase 2 (post-config): Call with diff containing ToDelete

SSL CA file storage is only available in HAProxy DataPlane API v3.2+. If the API version doesn't support CA file storage, operations are skipped with a warning.

The caller is responsible for splitting the diff into these phases. Returns reload IDs from create/update operations that triggered reloads.

func SyncSSLCertificates

func SyncSSLCertificates(ctx context.Context, c *client.DataplaneClient, diff *SSLCertificateDiff) ([]string, error)

SyncSSLCertificates synchronizes SSL certificates to the desired state by applying the provided diff. This function should be called in two phases:

  • Phase 1 (pre-config): Call with diff containing ToCreate and ToUpdate
  • Phase 2 (post-config): Call with diff containing ToDelete

The caller is responsible for splitting the diff into these phases. Returns reload IDs from create/update operations that triggered reloads.

Types

type CRTListDiff

type CRTListDiff = FileDiffGeneric[CRTListFile]

CRTListDiff is the diff produced for crt-list files. Alias of FileDiffGeneric[CRTListFile].

func CompareCRTLists

func CompareCRTLists(ctx context.Context, c *client.DataplaneClient, desired []CRTListFile) (*CRTListDiff, error)

CompareCRTLists compares the current state of crt-list files in HAProxy storage with the desired state, and returns a diff describing what needs to be created, updated, or deleted.

This function:

  1. Fetches all current crt-list file names from the Dataplane API
  2. Downloads content for each current crt-list file
  3. Compares with the desired crt-list files list
  4. Returns a CRTListDiff with operations needed to reach desired state

Path normalization: The API returns filenames only (e.g., "certificate-list.txt"), but CRTListFile.Path may contain full paths (e.g., "/etc/haproxy/certs/certificate-list.txt"). We normalize using path.Base() for comparison.

Storage strategy: Always uses general file storage instead of native CRT-list API. The native CRT-list API (POST ssl_crt_lists) triggers a reload but doesn't support the skip_reload parameter. General file CREATE returns 201 without triggering a reload, allowing us to batch all changes into a single reload during config sync.

type CRTListFile

type CRTListFile struct {
	// Path is the absolute file path to the crt-list file.
	// Example: "/etc/haproxy/crt-lists/crt-list.txt"
	Path string

	// Content is the crt-list file contents (one certificate entry per line).
	// Format: <cert-path> [ssl-options] [sni-filter]
	// Example: "/etc/haproxy/ssl/cert.pem [ocsp-update on] example.com"
	Content string
}

CRTListFile represents a HAProxy crt-list file for SSL certificate lists with per-certificate options. CRT-list files allow specifying multiple certificates with individual SSL options and SNI filters.

func (CRTListFile) GetContent

func (c CRTListFile) GetContent() string

GetContent implements the FileItem interface.

func (CRTListFile) GetIdentifier

func (c CRTListFile) GetIdentifier() string

GetIdentifier implements the FileItem interface.

type FileDiff

type FileDiff = FileDiffGeneric[GeneralFile]

FileDiff is the diff produced for general files. It is an alias of FileDiffGeneric[GeneralFile]; HasChanges and the underlying field set come from the generic type.

func CompareGeneralFiles

func CompareGeneralFiles(ctx context.Context, c *client.DataplaneClient, desired []GeneralFile) (*FileDiff, error)

CompareGeneralFiles compares the current state of general files in HAProxy storage with the desired state, and returns a diff describing what needs to be created, updated, or deleted.

This function:

  1. Fetches all current file paths from the Dataplane API
  2. Downloads content for each current file
  3. Compares with the desired files list
  4. Returns a FileDiff with operations needed to reach desired state

type FileDiffGeneric

type FileDiffGeneric[T FileItem] struct {
	// ToCreate contains files that exist in the desired state but not in the current state.
	ToCreate []T

	// ToUpdate contains files that exist in both states but have different content.
	ToUpdate []T

	// ToDelete contains identifiers of files that exist in the current state but not in the desired state.
	ToDelete []string
}

FileDiffGeneric represents the differences between current and desired file states.

This is a generic version of FileDiff/SSLCertificateDiff/MapFileDiff that works with any FileItem type.

func Compare

func Compare[T FileItem](
	ctx context.Context,
	ops FileOperations[T],
	desired []T,
	newFile func(id, content string) T,
) (*FileDiffGeneric[T], error)

Compare compares the current state of files with the desired state using generic operations.

This function:

  1. Fetches all current file identifiers from the API
  2. Downloads content for each current file
  3. Compares with the desired files list
  4. Returns a FileDiffGeneric with operations needed to reach desired state

Type Parameters:

  • T: The file item type (must implement FileItem interface)

Parameters:

  • ctx: Context for cancellation
  • ops: File operations adapter for the specific file type
  • desired: Desired file state
  • newFile: Constructor function to create a new file item from identifier and content

Returns:

  • *FileDiffGeneric[T]: Diff containing create, update, and delete operations
  • error: Any error encountered during comparison

func (*FileDiffGeneric[T]) HasChanges

func (d *FileDiffGeneric[T]) HasChanges() bool

HasChanges returns true if the diff contains any create, update, or delete operations.

type FileItem

type FileItem interface {
	// GetIdentifier returns the unique identifier for this file (filename or path).
	GetIdentifier() string

	// GetContent returns the file content.
	GetContent() string
}

FileItem represents any auxiliary file type (GeneralFile, SSLCertificate, MapFile).

All auxiliary file types must implement this interface to work with the generic Compare and Sync functions.

type FileOperations

type FileOperations[T FileItem] interface {
	// GetAll returns all file identifiers (filenames/paths) currently stored.
	GetAll(ctx context.Context) ([]string, error)

	// GetContent retrieves the content for a specific file by identifier.
	GetContent(ctx context.Context, id string) (string, error)

	// Create creates a new file with the given identifier and content.
	// Returns the reload ID if a reload was triggered (empty string if not).
	Create(ctx context.Context, id, content string) (string, error)

	// Update updates an existing file with new content.
	// Returns the reload ID if a reload was triggered (empty string if not).
	Update(ctx context.Context, id, content string) (string, error)

	// Delete removes a file by identifier.
	Delete(ctx context.Context, id string) error
}

FileOperations defines CRUD operations for a specific auxiliary file type.

Implementations wrap the DataplaneClient methods for general files, SSL certificates, or map files.

type GeneralFile

type GeneralFile struct {
	// Filename is the base file name (used as API 'id').
	// Example: "400.http"
	Filename string

	// Path is the absolute file path where the file is stored.
	// This is computed from the configured GeneralStorageDir + Filename.
	// Example: "/etc/haproxy/general/400.http"
	Path string

	// Content is the file contents as a string. This maps to the 'file' field in
	// multipart form uploads to the Dataplane API.
	Content string

	// IsCaFile marks this general file as an SSL CA / trust bundle referenced by
	// the config as `ca-file <path>` (frontend client-cert verify or backend mTLS
	// server verify). When set, a CONTENT-only update can be applied to the live
	// worker via the runtime API (`add ssl ca-file` + commit, which replaces the
	// file with the payload) without a reload on DataPlane API v3.2+ — the
	// orchestrator's runtime fast path keys off this flag. It is metadata only:
	// GetContent (used for diffing) ignores it, so it never causes a spurious diff
	// against the content-keyed current state.
	IsCaFile bool
}

GeneralFile represents a general-purpose file (error files, custom response files, etc.). These files are uploaded to the Dataplane API storage and can be referenced in the HAProxy configuration (e.g., in http-errors sections).

func CRTListsToGeneralFiles

func CRTListsToGeneralFiles(crtLists []CRTListFile) []GeneralFile

CRTListsToGeneralFiles converts CRT-list files to general files for storage. CRT-list files are stored as general files because the native CRT-list API (POST ssl_crt_lists) triggers a reload without supporting skip_reload parameter. General file CREATE returns 201 without triggering a reload.

This is also used by the orchestrator to merge CRT-lists into the unified general files comparison, since both are stored in general file storage.

IMPORTANT: Filenames are sanitized using client.SanitizeStorageName() to match how the HAProxy Dataplane API stores them. Without sanitization, comparison would fail because desired files (e.g., "example.com.txt") wouldn't match current files (e.g., "example_com.txt" - dots replaced with underscores).

func (GeneralFile) GetContent

func (g GeneralFile) GetContent() string

GetContent implements the FileItem interface.

func (GeneralFile) GetIdentifier

func (g GeneralFile) GetIdentifier() string

GetIdentifier implements the FileItem interface.

type MapFile

type MapFile struct {
	// Path is the absolute file path to the map file.
	// Example: "/etc/haproxy/maps/domains.map"
	Path string

	// Content is the map file contents (one key-value pair per line).
	Content string
}

MapFile represents a HAProxy map file for dynamic key-value lookups. Map files enable runtime configuration changes without reloading HAProxy.

func (MapFile) GetContent

func (m MapFile) GetContent() string

GetContent implements the FileItem interface.

func (MapFile) GetIdentifier

func (m MapFile) GetIdentifier() string

GetIdentifier implements the FileItem interface.

type MapFileDiff

type MapFileDiff = FileDiffGeneric[MapFile]

MapFileDiff is the diff produced for map files. Alias of FileDiffGeneric[MapFile].

func CompareMapFiles

func CompareMapFiles(ctx context.Context, c *client.DataplaneClient, desired []MapFile) (*MapFileDiff, error)

CompareMapFiles compares the current state of map files in HAProxy storage with the desired state, and returns a diff describing what needs to be created, updated, or deleted.

This function:

  1. Fetches all current map file names from the Dataplane API
  2. Downloads content for each current map file
  3. Compares with the desired map files list
  4. Returns a MapFileDiff with operations needed to reach desired state

type SSLCaFile

type SSLCaFile struct {
	// Path is the file path or name of the CA file.
	// Example: "ca-bundle.pem" or "/etc/haproxy/ssl/ca/trusted-cas.pem"
	Path string

	// Content is the PEM-encoded CA certificate data.
	// Can contain multiple CA certificates concatenated together.
	Content string
}

SSLCaFile represents an SSL CA certificate file containing trusted CA certificates. These files are used for client certificate verification and SSL chain validation. SSL CA file storage is only available in HAProxy DataPlane API v3.2+.

func (SSLCaFile) GetContent

func (s SSLCaFile) GetContent() string

GetContent implements the FileItem interface.

func (SSLCaFile) GetIdentifier

func (s SSLCaFile) GetIdentifier() string

GetIdentifier implements the FileItem interface.

type SSLCaFileDiff

type SSLCaFileDiff = FileDiffGeneric[SSLCaFile]

SSLCaFileDiff is the diff produced for SSL CA files. Alias of FileDiffGeneric[SSLCaFile].

func CompareSSLCaFiles

func CompareSSLCaFiles(ctx context.Context, c *client.DataplaneClient, desired []SSLCaFile) (*SSLCaFileDiff, error)

CompareSSLCaFiles compares the current state of SSL CA files in HAProxy storage with the desired state, and returns a diff describing what needs to be created, updated, or deleted.

SSL CA file storage is only available in HAProxy DataPlane API v3.2+. If the API version doesn't support CA file storage, returns an empty diff.

Strategy:

  1. Check if SSL CA file storage is supported
  2. Fetch current CA file names from the Dataplane API
  3. Download content for each current CA file
  4. Compare content with desired CA files
  5. Return diff with create, update, and delete operations

Path normalization: The API returns filenames only (e.g., "ca-bundle.pem"), but SSLCaFile.Path may contain full paths (e.g., "/etc/haproxy/ssl/ca/ca-bundle.pem"). We normalize using path.Base() for comparison (slash-only — these are HAProxy target paths regardless of host OS).

type SSLCertificate

type SSLCertificate struct {
	// Path is the absolute file path to the certificate.
	// Example: "/etc/haproxy/certs/example.com.pem"
	Path string

	// Content is the PEM-encoded certificate and key data.
	Content string
}

SSLCertificate represents an SSL/TLS certificate file containing certificates and keys. These files are used for HTTPS termination and client certificate authentication.

func (SSLCertificate) GetContent

func (s SSLCertificate) GetContent() string

GetContent implements the FileItem interface.

func (SSLCertificate) GetIdentifier

func (s SSLCertificate) GetIdentifier() string

GetIdentifier implements the FileItem interface.

type SSLCertificateDiff

type SSLCertificateDiff = FileDiffGeneric[SSLCertificate]

SSLCertificateDiff is the diff produced for SSL certificates. Alias of FileDiffGeneric[SSLCertificate].

func CompareSSLCertificates

func CompareSSLCertificates(ctx context.Context, c *client.DataplaneClient, desired []SSLCertificate) (*SSLCertificateDiff, error)

CompareSSLCertificates compares the current state of SSL certificates in HAProxy storage with the desired state, and returns a diff describing what needs to be created, updated, or deleted.

This function uses identifier-based comparison using certificate serial+issuer format. Both the API side and controller side use the same format ("cert:serial:XXX:issuers:YYY"), ensuring consistent comparison across all HAProxy DataPlane API versions.

Strategy:

  1. Fetch current certificate names from the Dataplane API
  2. Fetch identifiers for all current certificates (serial+issuer format)
  3. Compare identifiers with desired certificates
  4. Return diff with create, update, and delete operations

Path normalization: The API returns filenames only (e.g., "cert.pem"), but SSLCertificate.Path may contain full paths (e.g., "/etc/haproxy/ssl/cert.pem"). We normalize using path.Base() for comparison.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL