v1alpha1

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: 3 Imported by: 0

Documentation

Overview

Package v1alpha1 contains API Schema definitions for the haproxytemplate v1alpha1 API group.

Overview

This package defines the HAProxyTemplateConfig custom resource, which provides configuration for the HAProxy Template Ingress Controller as a Kubernetes-native CRD.

Key Features

  • Type-safe configuration with OpenAPI validation
  • Embedded validation tests for templates
  • Support for admission webhook validation
  • Credential reference management via Secrets

API Group

Group: haproxy-haptic.org Version: v1alpha1

Resources

HAProxyTemplateConfig: Controller configuration with embedded validation tests

Examples

See docs/controller/docs/development/crd-validation-design.md for comprehensive examples and usage patterns.

+k8s:deepcopy-gen=package +groupName=haproxy-haptic.org

Index

Constants

View Source
const (
	// GroupName is the group name for this API.
	GroupName = "haproxy-haptic.org"

	// Version is the version for this API.
	Version = "v1alpha1"
)

Variables

View Source
var (
	// SchemeGroupVersion is the group version used to register these objects.
	SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: Version}

	// SchemeBuilder is used to add go types to the GroupVersionKind scheme.
	SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)

	// AddToScheme adds the types in this group-version to the given scheme.
	AddToScheme = SchemeBuilder.AddToScheme
)

Functions

func Resource

func Resource(resource string) schema.GroupResource

Resource takes an unqualified resource and returns a Group qualified GroupResource.

Types

type AuxiliaryFileReferences

type AuxiliaryFileReferences struct {
	// MapFiles lists the HAProxyMapFile resources associated with this config.
	// +optional
	MapFiles []ResourceReference `json:"mapFiles,omitempty"`

	// SSLCertificates lists the Secret resources containing SSL certificates.
	// +optional
	SSLCertificates []ResourceReference `json:"sslCertificates,omitempty"`

	// GeneralFiles lists the HAProxyGeneralFile resources associated with this config.
	// +optional
	GeneralFiles []ResourceReference `json:"generalFiles,omitempty"`

	// CRTListFiles lists the HAProxyCRTListFile resources associated with this config.
	// +optional
	CRTListFiles []ResourceReference `json:"crtListFiles,omitempty"`
}

AuxiliaryFileReferences references the associated map files, certificates, general files, and crt-lists.

func (*AuxiliaryFileReferences) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuxiliaryFileReferences.

func (*AuxiliaryFileReferences) DeepCopyInto

func (in *AuxiliaryFileReferences) DeepCopyInto(out *AuxiliaryFileReferences)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ConfigPublishingConfig

type ConfigPublishingConfig struct {
	// CompressionThreshold is the minimum size in bytes at which configs are compressed.
	//
	// Configs smaller than this threshold are stored uncompressed.
	// Compression uses zstd+base64 encoding.
	//
	// Default: 1048576 (1 MiB)
	// Set to 0 to disable compression.
	// +kubebuilder:validation:Minimum=0
	// +kubebuilder:default=1048576
	// +optional
	CompressionThreshold int64 `json:"compressionThreshold,omitempty"`
}

ConfigPublishingConfig configures how rendered configs are stored in CRDs.

func (*ConfigPublishingConfig) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigPublishingConfig.

func (*ConfigPublishingConfig) DeepCopyInto

func (in *ConfigPublishingConfig) DeepCopyInto(out *ConfigPublishingConfig)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ControllerConfig

type ControllerConfig struct {
	// LeaderElection configures leader election for high availability.
	// +optional
	LeaderElection LeaderElectionConfig `json:"leaderElection,omitempty"`

	// ConfigPublishing configures how rendered configs are stored in CRDs.
	// +optional
	ConfigPublishing ConfigPublishingConfig `json:"configPublishing,omitempty"`
}

ControllerConfig contains controller-level configuration.

func (*ControllerConfig) DeepCopy

func (in *ControllerConfig) DeepCopy() *ControllerConfig

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ControllerConfig.

func (*ControllerConfig) DeepCopyInto

func (in *ControllerConfig) DeepCopyInto(out *ControllerConfig)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type DataplaneConfig

type DataplaneConfig struct {
	// Port is the Dataplane API port for production HAProxy pods.
	//
	// Default: 5555
	// +kubebuilder:validation:Minimum=1
	// +kubebuilder:validation:Maximum=65535
	// +optional
	Port int `json:"port,omitempty"`

	// MinDeploymentInterval enforces minimum time between consecutive deployments.
	//
	// This prevents rapid-fire deployments from hammering HAProxy instances.
	// Format: Go duration string (e.g., "2s", "500ms")
	// Default: 2s
	// +optional
	MinDeploymentInterval string `json:"minDeploymentInterval,omitempty"`

	// DriftPreventionInterval triggers periodic deployments to prevent configuration drift.
	//
	// A deployment is automatically triggered if no deployment has occurred within this interval.
	// This detects and corrects drift caused by external Dataplane API clients.
	// Format: Go duration string (e.g., "60s", "5m")
	// Default: 60s
	// +optional
	DriftPreventionInterval string `json:"driftPreventionInterval,omitempty"`

	// MapsDir is the directory for HAProxy map files.
	//
	// Used for both validation and deployment.
	// Default: /etc/haproxy/maps
	// +optional
	MapsDir string `json:"mapsDir,omitempty"`

	// SSLCertsDir is the directory for SSL certificates.
	//
	// Used for both validation and deployment.
	// Default: /etc/haproxy/ssl
	// +optional
	SSLCertsDir string `json:"sslCertsDir,omitempty"`

	// GeneralStorageDir is the directory for general files (error pages, etc.).
	//
	// Used for both validation and deployment.
	// Default: /etc/haproxy/general
	// +optional
	GeneralStorageDir string `json:"generalStorageDir,omitempty"`

	// ConfigFile is the path to the main HAProxy configuration file.
	//
	// Used for validation.
	// Default: /etc/haproxy/haproxy.cfg
	// +optional
	ConfigFile string `json:"configFile,omitempty"`

	// DeploymentTimeout is the maximum time to wait for a deployment to complete.
	// If exceeded, the scheduler assumes the deployment was lost and retries.
	// This is a safety net for race conditions during leadership transitions.
	// Format: Go duration string (e.g., "30s", "1m")
	// Default: 30s
	// +optional
	DeploymentTimeout string `json:"deploymentTimeout,omitempty"`

	// ConfigPublishInterval throttles how often the rendered HAProxy config is
	// republished as the HAProxyCfg observability CRD. The CRD itself is not on
	// the deployment hot path, but during endpoint churn rewriting the (~500 KB)
	// CRD on every reconciliation creates significant etcd write pressure;
	// throttling republishes reduces that write load while leaving the
	// event-driven push to HAProxy pods untouched.
	//
	// Format: Go duration string (e.g., "10s", "1m").
	// Default: 10s
	// +optional
	ConfigPublishInterval string `json:"configPublishInterval,omitempty"`

	// ReloadVerificationTimeout is the maximum time the Dataplane sync waits for
	// HAProxy to report a graceful reload as completed before failing the sync.
	// Set this higher than the Dataplane API's own reload-delay setting.
	//
	// Format: Go duration string (e.g., "10s", "30s").
	// Default: 10s
	// +optional
	ReloadVerificationTimeout string `json:"reloadVerificationTimeout,omitempty"`

	// SyncTimeout is the overall timeout for a single Dataplane sync to one
	// HAProxy endpoint. The sync covers parse + diff + raw config push +
	// optional reload-verification. If exceeded, the sync is cancelled and the
	// scheduler retries on the next reconciliation.
	//
	// Format: Go duration string (e.g., "2m", "30s").
	// Default: 2m
	// +optional
	SyncTimeout string `json:"syncTimeout,omitempty"`
}

DataplaneConfig configures the Dataplane API for production HAProxy instances.

func (*DataplaneConfig) DeepCopy

func (in *DataplaneConfig) DeepCopy() *DataplaneConfig

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DataplaneConfig.

func (*DataplaneConfig) DeepCopyInto

func (in *DataplaneConfig) DeepCopyInto(out *DataplaneConfig)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type GeneralFile

type GeneralFile struct {
	// Template is the template for generating the file content.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Template string `json:"template"`

	// PostProcessing defines optional post-processors to apply after rendering.
	//
	// Post-processors run in the order specified and can transform the rendered output.
	// +optional
	PostProcessing []PostProcessorConfig `json:"postProcessing,omitempty"`
}

GeneralFile defines a general file generated from a template.

The filename is derived from the map key in the configuration. The full path is constructed using the pathResolver.GetPath() method in templates:

Example: pathResolver.GetPath("503.http", "file") returns /etc/haproxy/general/503.http

IMPORTANT: This is a Kubernetes CRD type. When modifying this struct, you must also update:

  • The internal config type: pkg/core/config/types.go (GeneralFile)
  • The conversion logic: pkg/controller/conversion/converter.go (ConvertSpec function - files section)

func (*GeneralFile) DeepCopy

func (in *GeneralFile) DeepCopy() *GeneralFile

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GeneralFile.

func (*GeneralFile) DeepCopyInto

func (in *GeneralFile) DeepCopyInto(out *GeneralFile)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HAProxyCRTListFile

type HAProxyCRTListFile struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   HAProxyCRTListFileSpec   `json:"spec,omitempty"`
	Status HAProxyCRTListFileStatus `json:"status,omitempty"`
}

HAProxyCRTListFile contains a rendered HAProxy crt-list file.

CRT-list files contain SSL certificate references with per-certificate options and SNI filters. This is a read-only resource automatically created and updated by the controller. Each HAProxyCRTListFile is owned by a HAProxyCfg resource.

func (*HAProxyCRTListFile) DeepCopy

func (in *HAProxyCRTListFile) DeepCopy() *HAProxyCRTListFile

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyCRTListFile.

func (*HAProxyCRTListFile) DeepCopyInto

func (in *HAProxyCRTListFile) DeepCopyInto(out *HAProxyCRTListFile)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*HAProxyCRTListFile) DeepCopyObject

func (in *HAProxyCRTListFile) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type HAProxyCRTListFileList

type HAProxyCRTListFileList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []HAProxyCRTListFile `json:"items"`
}

HAProxyCRTListFileList contains a list of HAProxyCRTListFile.

func (*HAProxyCRTListFileList) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyCRTListFileList.

func (*HAProxyCRTListFileList) DeepCopyInto

func (in *HAProxyCRTListFileList) DeepCopyInto(out *HAProxyCRTListFileList)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*HAProxyCRTListFileList) DeepCopyObject

func (in *HAProxyCRTListFileList) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type HAProxyCRTListFileSpec

type HAProxyCRTListFileSpec struct {
	// ListName is the logical name of the crt-list file.
	//
	// Example: "frontend-certs" or "backend-client-certs"
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	ListName string `json:"listName"`

	// Path is the file system path where this crt-list file is stored.
	//
	// Example: /etc/haproxy/crt-lists/frontend.crtlist
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Path string `json:"path"`

	// Entries is the crt-list file content.
	//
	// Each line contains a certificate path with optional SSL options and SNI filters.
	// Format: <cert-path> [ssl-options] [sni-filter]
	// Example:
	//   /etc/haproxy/ssl/example.com.pem [ocsp-update on] example.com
	//   /etc/haproxy/ssl/wildcard.pem *.example.org
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Entries string `json:"entries"`

	// Checksum is the SHA-256 hash of the crt-list entries.
	//
	// Used to detect changes and verify consistency across pods.
	// Format: sha256:<hex-digest>
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Checksum string `json:"checksum"`

	// Compressed indicates the entries are zstd+base64 encoded.
	//
	// When true, consumers must decompress before use.
	// +optional
	Compressed bool `json:"compressed,omitempty"`
}

HAProxyCRTListFileSpec contains the crt-list file content.

func (*HAProxyCRTListFileSpec) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyCRTListFileSpec.

func (*HAProxyCRTListFileSpec) DeepCopyInto

func (in *HAProxyCRTListFileSpec) DeepCopyInto(out *HAProxyCRTListFileSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HAProxyCRTListFileStatus

type HAProxyCRTListFileStatus struct {
	// DeployedToPods tracks which HAProxy pods currently have this crt-list file.
	//
	// Pods are automatically added when the crt-list file is applied and removed when
	// the pod terminates.
	// +optional
	// +listType=map
	// +listMapKey=podName
	DeployedToPods []PodDeploymentStatus `json:"deployedToPods,omitempty"`

	// ObservedGeneration reflects the generation of the spec that was most recently processed.
	//
	// This is used to track whether status is up-to-date with latest spec changes.
	// +optional
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`

	// Conditions represent the latest available observations of the resource's state.
	//
	// Standard conditions include:
	// - "Synced": CRT-list file has been successfully applied to all target pods
	// - "Ready": Resource is ready for use
	// +optional
	// +patchMergeKey=type
	// +patchStrategy=merge
	// +listType=map
	// +listMapKey=type
	Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
}

HAProxyCRTListFileStatus tracks deployment state to HAProxy pods.

func (*HAProxyCRTListFileStatus) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyCRTListFileStatus.

func (*HAProxyCRTListFileStatus) DeepCopyInto

func (in *HAProxyCRTListFileStatus) DeepCopyInto(out *HAProxyCRTListFileStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HAProxyCfg

type HAProxyCfg struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   HAProxyCfgSpec   `json:"spec,omitempty"`
	Status HAProxyCfgStatus `json:"status,omitempty"`
}

HAProxyCfg contains the rendered HAProxy configuration for a specific HAProxyTemplateConfig.

This is a read-only resource automatically created and updated by the controller to expose the actual runtime configuration applied to HAProxy pods.

func (*HAProxyCfg) DeepCopy

func (in *HAProxyCfg) DeepCopy() *HAProxyCfg

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyCfg.

func (*HAProxyCfg) DeepCopyInto

func (in *HAProxyCfg) DeepCopyInto(out *HAProxyCfg)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*HAProxyCfg) DeepCopyObject

func (in *HAProxyCfg) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type HAProxyCfgList

type HAProxyCfgList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []HAProxyCfg `json:"items"`
}

HAProxyCfgList contains a list of HAProxyCfg.

func (*HAProxyCfgList) DeepCopy

func (in *HAProxyCfgList) DeepCopy() *HAProxyCfgList

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyCfgList.

func (*HAProxyCfgList) DeepCopyInto

func (in *HAProxyCfgList) DeepCopyInto(out *HAProxyCfgList)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*HAProxyCfgList) DeepCopyObject

func (in *HAProxyCfgList) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type HAProxyCfgSpec

type HAProxyCfgSpec struct {
	// Path is the file system path where this configuration is stored.
	//
	// Default: /etc/haproxy/haproxy.cfg
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Path string `json:"path"`

	// Content is the rendered HAProxy configuration file content.
	//
	// This is the actual haproxy.cfg content that was validated and deployed
	// to HAProxy pods.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Content string `json:"content"`

	// Checksum is the SHA-256 hash of the original (uncompressed) configuration content.
	//
	// Used to detect configuration changes and verify consistency across pods.
	// Format: sha256:<hex-digest>
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Checksum string `json:"checksum"`

	// Compressed indicates the content is zstd+base64 encoded.
	//
	// When true, consumers must decompress before use.
	// +optional
	Compressed bool `json:"compressed,omitempty"`
}

HAProxyCfgSpec contains the rendered configuration content.

func (*HAProxyCfgSpec) DeepCopy

func (in *HAProxyCfgSpec) DeepCopy() *HAProxyCfgSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyCfgSpec.

func (*HAProxyCfgSpec) DeepCopyInto

func (in *HAProxyCfgSpec) DeepCopyInto(out *HAProxyCfgSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HAProxyCfgStatus

type HAProxyCfgStatus struct {
	// DeployedToPods tracks which HAProxy pods currently have this configuration.
	//
	// Pods are automatically added when configuration is applied and removed when
	// the pod terminates.
	//
	// The list is keyed by podName so each pod's status update can land via
	// Server-Side Apply with its own field manager — concurrent updates from
	// different pods merge naturally instead of last-write-wins on the
	// full-object UpdateStatus path that preceded this CRD shape.
	// +optional
	// +listType=map
	// +listMapKey=podName
	DeployedToPods []PodDeploymentStatus `json:"deployedToPods,omitempty"`

	// AuxiliaryFiles references the associated map files and certificates.
	// +optional
	AuxiliaryFiles *AuxiliaryFileReferences `json:"auxiliaryFiles,omitempty"`

	// ValidationError contains the error message if this configuration failed validation.
	//
	// Only populated for HAProxyCfg resources published with the -invalid suffix.
	// When present, this configuration was not deployed to HAProxy instances.
	// +optional
	ValidationError string `json:"validationError,omitempty"`

	// ObservedGeneration reflects the generation of the spec that was most recently processed.
	//
	// This is used to track whether status is up-to-date with latest spec changes.
	// +optional
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`

	// Conditions represent the latest available observations of the resource's state.
	//
	// Standard conditions include:
	// - "Synced": Configuration has been successfully applied to all target pods
	// - "Ready": Resource is ready for use
	// +optional
	// +patchMergeKey=type
	// +patchStrategy=merge
	// +listType=map
	// +listMapKey=type
	Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
}

HAProxyCfgStatus tracks deployment state and auxiliary files.

func (*HAProxyCfgStatus) DeepCopy

func (in *HAProxyCfgStatus) DeepCopy() *HAProxyCfgStatus

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyCfgStatus.

func (*HAProxyCfgStatus) DeepCopyInto

func (in *HAProxyCfgStatus) DeepCopyInto(out *HAProxyCfgStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HAProxyConfig

type HAProxyConfig struct {
	// Template is the template for generating haproxy.cfg.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Template string `json:"template"`

	// PostProcessing defines optional post-processors to apply after rendering.
	//
	// Post-processors run in the order specified and can transform the rendered output.
	// Common use case: Normalize indentation with regex_replace.
	// +optional
	PostProcessing []PostProcessorConfig `json:"postProcessing,omitempty"`
}

HAProxyConfig defines the main HAProxy configuration.

IMPORTANT: This is a Kubernetes CRD type. When modifying this struct, you must also update:

  • The internal config type: pkg/core/config/types.go (HAProxyConfig)
  • The conversion logic: pkg/controller/conversion/converter.go (ConvertSpec function - haproxyConfig section)

func (*HAProxyConfig) DeepCopy

func (in *HAProxyConfig) DeepCopy() *HAProxyConfig

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyConfig.

func (*HAProxyConfig) DeepCopyInto

func (in *HAProxyConfig) DeepCopyInto(out *HAProxyConfig)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HAProxyGeneralFile

type HAProxyGeneralFile struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   HAProxyGeneralFileSpec   `json:"spec,omitempty"`
	Status HAProxyGeneralFileStatus `json:"status,omitempty"`
}

HAProxyGeneralFile contains a rendered HAProxy general file (error pages, custom responses, etc.).

This is a read-only resource automatically created and updated by the controller to expose general files generated from templates. Each HAProxyGeneralFile is owned by a HAProxyCfg resource.

func (*HAProxyGeneralFile) DeepCopy

func (in *HAProxyGeneralFile) DeepCopy() *HAProxyGeneralFile

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyGeneralFile.

func (*HAProxyGeneralFile) DeepCopyInto

func (in *HAProxyGeneralFile) DeepCopyInto(out *HAProxyGeneralFile)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*HAProxyGeneralFile) DeepCopyObject

func (in *HAProxyGeneralFile) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type HAProxyGeneralFileList

type HAProxyGeneralFileList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []HAProxyGeneralFile `json:"items"`
}

HAProxyGeneralFileList contains a list of HAProxyGeneralFile.

func (*HAProxyGeneralFileList) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyGeneralFileList.

func (*HAProxyGeneralFileList) DeepCopyInto

func (in *HAProxyGeneralFileList) DeepCopyInto(out *HAProxyGeneralFileList)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*HAProxyGeneralFileList) DeepCopyObject

func (in *HAProxyGeneralFileList) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type HAProxyGeneralFileSpec

type HAProxyGeneralFileSpec struct {
	// FileName is the logical name of the file.
	//
	// This corresponds to the key in HAProxyTemplateConfig.spec.files.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	FileName string `json:"fileName"`

	// Path is the file system path where this file is stored.
	//
	// Example: /etc/haproxy/general/503.http
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Path string `json:"path"`

	// Content is the file content.
	//
	// This can be any content the HAProxy configuration references,
	// such as custom error pages or response files.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Content string `json:"content"`

	// Checksum is the SHA-256 hash of the file content.
	//
	// Used to detect changes and verify consistency across pods.
	// Format: sha256:<hex-digest>
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Checksum string `json:"checksum"`

	// Compressed indicates the content is zstd+base64 encoded.
	//
	// When true, consumers must decompress before use.
	// +optional
	Compressed bool `json:"compressed,omitempty"`
}

HAProxyGeneralFileSpec contains the general file content.

func (*HAProxyGeneralFileSpec) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyGeneralFileSpec.

func (*HAProxyGeneralFileSpec) DeepCopyInto

func (in *HAProxyGeneralFileSpec) DeepCopyInto(out *HAProxyGeneralFileSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HAProxyGeneralFileStatus

type HAProxyGeneralFileStatus struct {
	// DeployedToPods tracks which HAProxy pods currently have this file.
	//
	// Pods are automatically added when the file is applied and removed when
	// the pod terminates.
	// +optional
	// +listType=map
	// +listMapKey=podName
	DeployedToPods []PodDeploymentStatus `json:"deployedToPods,omitempty"`

	// ObservedGeneration reflects the generation of the spec that was most recently processed.
	//
	// This is used to track whether status is up-to-date with latest spec changes.
	// +optional
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`

	// Conditions represent the latest available observations of the resource's state.
	//
	// Standard conditions include:
	// - "Synced": File has been successfully applied to all target pods
	// - "Ready": Resource is ready for use
	// +optional
	// +patchMergeKey=type
	// +patchStrategy=merge
	// +listType=map
	// +listMapKey=type
	Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
}

HAProxyGeneralFileStatus tracks deployment state to HAProxy pods.

func (*HAProxyGeneralFileStatus) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyGeneralFileStatus.

func (*HAProxyGeneralFileStatus) DeepCopyInto

func (in *HAProxyGeneralFileStatus) DeepCopyInto(out *HAProxyGeneralFileStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HAProxyMapFile

type HAProxyMapFile struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   HAProxyMapFileSpec   `json:"spec,omitempty"`
	Status HAProxyMapFileStatus `json:"status,omitempty"`
}

HAProxyMapFile contains a rendered HAProxy map file.

This is a read-only resource automatically created and updated by the controller to expose map files generated from templates. Each HAProxyMapFile is owned by a HAProxyConfig resource.

func (*HAProxyMapFile) DeepCopy

func (in *HAProxyMapFile) DeepCopy() *HAProxyMapFile

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyMapFile.

func (*HAProxyMapFile) DeepCopyInto

func (in *HAProxyMapFile) DeepCopyInto(out *HAProxyMapFile)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*HAProxyMapFile) DeepCopyObject

func (in *HAProxyMapFile) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type HAProxyMapFileList

type HAProxyMapFileList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []HAProxyMapFile `json:"items"`
}

HAProxyMapFileList contains a list of HAProxyMapFile.

func (*HAProxyMapFileList) DeepCopy

func (in *HAProxyMapFileList) DeepCopy() *HAProxyMapFileList

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyMapFileList.

func (*HAProxyMapFileList) DeepCopyInto

func (in *HAProxyMapFileList) DeepCopyInto(out *HAProxyMapFileList)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*HAProxyMapFileList) DeepCopyObject

func (in *HAProxyMapFileList) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type HAProxyMapFileSpec

type HAProxyMapFileSpec struct {
	// MapName is the logical name of the map file.
	//
	// This corresponds to the key in HAProxyTemplateConfig.spec.maps.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	MapName string `json:"mapName"`

	// Path is the file system path where this map file is stored.
	//
	// Example: /etc/haproxy/maps/path-prefix.map
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Path string `json:"path"`

	// Entries is the map file content in HAProxy map format.
	//
	// Each line typically contains a key-value pair separated by whitespace.
	// Example:
	//   /api backend-api
	//   /web backend-web
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Entries string `json:"entries"`

	// Checksum is the SHA-256 hash of the map file entries.
	//
	// Used to detect changes and verify consistency across pods.
	// Format: sha256:<hex-digest>
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Checksum string `json:"checksum"`

	// Compressed indicates the entries are zstd+base64 encoded.
	//
	// When true, consumers must decompress before use.
	// +optional
	Compressed bool `json:"compressed,omitempty"`
}

HAProxyMapFileSpec contains the map file content.

func (*HAProxyMapFileSpec) DeepCopy

func (in *HAProxyMapFileSpec) DeepCopy() *HAProxyMapFileSpec

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyMapFileSpec.

func (*HAProxyMapFileSpec) DeepCopyInto

func (in *HAProxyMapFileSpec) DeepCopyInto(out *HAProxyMapFileSpec)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HAProxyMapFileStatus

type HAProxyMapFileStatus struct {
	// DeployedToPods tracks which HAProxy pods currently have this map file.
	//
	// Pods are automatically added when the map file is applied and removed when
	// the pod terminates.
	// +optional
	// +listType=map
	// +listMapKey=podName
	DeployedToPods []PodDeploymentStatus `json:"deployedToPods,omitempty"`

	// ObservedGeneration reflects the generation of the spec that was most recently processed.
	//
	// This is used to track whether status is up-to-date with latest spec changes.
	// +optional
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`

	// Conditions represent the latest available observations of the resource's state.
	//
	// Standard conditions include:
	// - "Synced": Map file has been successfully applied to all target pods
	// - "Ready": Resource is ready for use
	// +optional
	// +patchMergeKey=type
	// +patchStrategy=merge
	// +listType=map
	// +listMapKey=type
	Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type"`
}

HAProxyMapFileStatus tracks deployment state to HAProxy pods.

func (*HAProxyMapFileStatus) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyMapFileStatus.

func (*HAProxyMapFileStatus) DeepCopyInto

func (in *HAProxyMapFileStatus) DeepCopyInto(out *HAProxyMapFileStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HAProxyTemplateConfig

type HAProxyTemplateConfig struct {
	metav1.TypeMeta   `json:",inline"`
	metav1.ObjectMeta `json:"metadata,omitempty"`

	Spec   HAProxyTemplateConfigSpec   `json:"spec,omitempty"`
	Status HAProxyTemplateConfigStatus `json:"status,omitempty"`
}

HAProxyTemplateConfig defines the configuration for the HAProxy Template Ingress Controller.

As a custom resource it provides OpenAPI validation, type safety, and support for embedded validation tests.

func (*HAProxyTemplateConfig) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyTemplateConfig.

func (*HAProxyTemplateConfig) DeepCopyInto

func (in *HAProxyTemplateConfig) DeepCopyInto(out *HAProxyTemplateConfig)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*HAProxyTemplateConfig) DeepCopyObject

func (in *HAProxyTemplateConfig) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type HAProxyTemplateConfigList

type HAProxyTemplateConfigList struct {
	metav1.TypeMeta `json:",inline"`
	metav1.ListMeta `json:"metadata,omitempty"`
	Items           []HAProxyTemplateConfig `json:"items"`
}

HAProxyTemplateConfigList contains a list of HAProxyTemplateConfig.

func (*HAProxyTemplateConfigList) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyTemplateConfigList.

func (*HAProxyTemplateConfigList) DeepCopyInto

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

func (*HAProxyTemplateConfigList) DeepCopyObject

func (in *HAProxyTemplateConfigList) DeepCopyObject() runtime.Object

DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.

type HAProxyTemplateConfigSpec

type HAProxyTemplateConfigSpec struct {
	// CredentialsSecretRef references the Secret containing HAProxy Dataplane API credentials.
	//
	// The Secret must contain the following keys:
	//   - dataplane_username: Username for HAProxy Dataplane API
	//   - dataplane_password: Password for HAProxy Dataplane API
	//
	// If the namespace is omitted, it defaults to the same namespace as this config resource.
	// +kubebuilder:validation:Required
	CredentialsSecretRef SecretReference `json:"credentialsSecretRef"`

	// PodSelector identifies which HAProxy pods to configure.
	// +kubebuilder:validation:Required
	PodSelector PodSelector `json:"podSelector"`

	// Controller contains controller-level settings (ports, leader election, etc.).
	// +optional
	Controller ControllerConfig `json:"controller,omitempty"`

	// Logging configures logging behavior.
	// +optional
	Logging LoggingConfig `json:"logging,omitempty"`

	// Dataplane configures the Dataplane API for production HAProxy instances.
	// +optional
	Dataplane DataplaneConfig `json:"dataplane,omitempty"`

	// TemplatingSettings configures template rendering behavior and custom variables.
	// +optional
	TemplatingSettings TemplatingSettings `json:"templatingSettings,omitempty"`

	// WatchedResourcesIgnoreFields specifies JSONPath expressions for fields
	// to remove from all watched resources to reduce memory usage.
	//
	// Example: ["metadata.managedFields", "metadata.resourceVersion"]
	// +optional
	WatchedResourcesIgnoreFields []string `json:"watchedResourcesIgnoreFields,omitempty"`

	// WatchedResources maps resource type names to their watch configuration.
	//
	// Each key is a user-defined name for the resource type (e.g., "ingresses", "services").
	// This name is used in templates to access the resources.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinProperties=1
	WatchedResources map[string]WatchedResource `json:"watchedResources"`

	// Validators declares pluggable validator sidecars consulted by the
	// admission webhook before admitting changes that affect plugin
	// configuration. See `docs/controller/docs/operations/pluggable-validators.md`
	// for setup; the wire protocol is at
	// `docs/development/validator-protocol.md`.
	//
	// An empty list (the default) disables pluggable validation — the
	// webhook keeps performing template + HAProxy syntax dry-run only.
	// +optional
	// +listType=map
	// +listMapKey=name
	Validators []ValidatorConfig `json:"validators,omitempty"`

	// TemplateSnippets maps snippet names to reusable template fragments.
	//
	// Snippets can be included in other templates using {{ render "name" }}.
	// +optional
	TemplateSnippets map[string]TemplateSnippet `json:"templateSnippets,omitempty"`

	// Maps maps map file names to their template definitions.
	//
	// These generate HAProxy map files for backend routing and other features.
	// +optional
	Maps map[string]MapFile `json:"maps,omitempty"`

	// Files maps file names to their template definitions.
	//
	// These generate auxiliary files like custom error pages.
	// +optional
	Files map[string]GeneralFile `json:"files,omitempty"`

	// SSLCertificates maps certificate names to their template definitions.
	//
	// These generate SSL certificate files for HAProxy.
	// +optional
	SSLCertificates map[string]SSLCertificate `json:"sslCertificates,omitempty"`

	// K8sResources maps resource template names to their template
	// definitions. Each entry's rendered output is parsed as one or
	// more Kubernetes resources (multi-doc YAML, separated by `---`)
	// and applied via Server-Side Apply with field manager `haptic`.
	//
	// The controller injects an OwnerReference to the
	// HAProxyTemplateConfig CR (controller=true,
	// blockOwnerDeletion=true) on every applied resource so cascade
	// garbage collection removes them when the CR is deleted (e.g.
	// `helm uninstall`). Resources that disappear from the rendered
	// set across reconciliations are pruned via the
	// `haproxy-haptic.org/managed-by` label the applier injects.
	//
	// Templates have full access to the same engine context as
	// haproxyConfig — `resources`, filters, `templateSnippets`,
	// `fileRegistry`, `extraContext`, etc. — so a k8sResources
	// template can render extension points (`render_glob` patterns)
	// and consume cached state (`shared.ComputeIfAbsent`).
	// +optional
	K8sResources map[string]K8sResource `json:"k8sResources,omitempty"`

	// HAProxyConfig contains the main HAProxy configuration template.
	// +kubebuilder:validation:Required
	HAProxyConfig HAProxyConfig `json:"haproxyConfig"`

	// ValidationTests contains embedded validation test definitions.
	//
	// The map key is the test name, which must be unique.
	//
	// These tests are executed:
	//   - During admission webhook validation (before resource is saved)
	//   - Via the "controller validate" CLI command (pre-apply validation)
	//
	// Tests ensure templates generate valid HAProxy configurations before deployment.
	// +optional
	ValidationTests map[string]ValidationTest `json:"validationTests,omitempty"`
}

HAProxyTemplateConfigSpec defines the desired state of HAProxyTemplateConfig.

func (*HAProxyTemplateConfigSpec) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyTemplateConfigSpec.

func (*HAProxyTemplateConfigSpec) DeepCopyInto

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HAProxyTemplateConfigStatus

type HAProxyTemplateConfigStatus struct {
	// ObservedGeneration reflects the generation most recently observed by the controller.
	// +optional
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`

	// LastValidated is the timestamp of the last successful validation.
	// +optional
	LastValidated *metav1.Time `json:"lastValidated,omitempty"`

	// ValidationStatus indicates the overall validation status.
	// +kubebuilder:validation:Enum=Valid;Invalid;Unknown
	// +optional
	ValidationStatus string `json:"validationStatus,omitempty"`

	// ValidationMessage contains human-readable validation details.
	// +optional
	ValidationMessage string `json:"validationMessage,omitempty"`

	// ValidationErrors contains detailed validation error messages.
	// Each entry includes the template name, error location, and context.
	// +optional
	ValidationErrors []string `json:"validationErrors,omitempty"`

	// Conditions represent the latest available observations of the config's state.
	// +optional
	Conditions []metav1.Condition `json:"conditions,omitempty"`
}

HAProxyTemplateConfigStatus defines the observed state of HAProxyTemplateConfig.

func (*HAProxyTemplateConfigStatus) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HAProxyTemplateConfigStatus.

func (*HAProxyTemplateConfigStatus) DeepCopyInto

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type HTTPResourceFixture

type HTTPResourceFixture struct {
	// URL is the HTTP URL to mock.
	//
	// When http.Fetch() is called with this URL during test execution,
	// the Content field is returned instead of fetching from the network.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	URL string `json:"url"`

	// Content is the mock response body to return.
	//
	// This content is returned when http.Fetch() is called with the
	// matching URL during test execution.
	// +kubebuilder:validation:Required
	Content string `json:"content"`
}

HTTPResourceFixture defines mock HTTP content for validation tests.

When templates call http.Fetch() for the specified URL, the pre-defined content is returned instead of making an actual HTTP request.

func (*HTTPResourceFixture) DeepCopy

func (in *HTTPResourceFixture) DeepCopy() *HTTPResourceFixture

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPResourceFixture.

func (*HTTPResourceFixture) DeepCopyInto

func (in *HTTPResourceFixture) DeepCopyInto(out *HTTPResourceFixture)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type K8sResource

type K8sResource struct {
	// Template is the template for generating the resource YAML.
	//
	// The rendered output is parsed as one or more Kubernetes
	// resources (separate documents with `---`). Each document must
	// declare `apiVersion`, `kind`, and `metadata.name` (plus
	// `metadata.namespace` for namespaced kinds).
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Template string `json:"template"`

	// PostProcessing defines optional post-processors to apply after rendering.
	//
	// Post-processors run in the order specified and can transform the rendered output.
	// +optional
	PostProcessing []PostProcessorConfig `json:"postProcessing,omitempty"`
}

K8sResource defines a template that emits one or more Kubernetes resources via multi-doc YAML.

IMPORTANT: This is a Kubernetes CRD type. When modifying this struct, you must also update:

  • The internal config type: pkg/core/config/types.go (K8sResource)
  • The conversion logic: pkg/controller/conversion/converter.go (ConvertSpec function - k8sResources section)

func (*K8sResource) DeepCopy

func (in *K8sResource) DeepCopy() *K8sResource

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new K8sResource.

func (*K8sResource) DeepCopyInto

func (in *K8sResource) DeepCopyInto(out *K8sResource)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type LeaderElectionConfig

type LeaderElectionConfig struct {
	// Enabled determines whether leader election is active.
	//
	// If false, the controller assumes it is the sole instance (single-replica mode).
	// Default: true
	// +optional
	Enabled *bool `json:"enabled,omitempty"`

	// LeaseName is the name of the Lease resource used for coordination.
	//
	// Default: haptic-leader
	// +kubebuilder:validation:MinLength=1
	// +optional
	LeaseName string `json:"leaseName,omitempty"`

	// LeaseDuration is the duration that non-leader candidates will wait
	// to force acquire leadership (measured against time of last observed ack).
	//
	// Format: Go duration string (e.g., "15s", "30s")
	// Default: 30s (DefaultLeaderElectionLeaseDuration in pkg/core/config/defaults.go;
	// the Helm chart's values.yaml sets the same value at controller.config.controller.leaderElection.leaseDuration)
	// +optional
	LeaseDuration string `json:"leaseDuration,omitempty"`

	// RenewDeadline is the duration that the acting leader will retry
	// refreshing leadership before giving up.
	//
	// Format: Go duration string (e.g., "20s")
	// Default: 20s (DefaultLeaderElectionRenewDeadline)
	// Must be less than LeaseDuration
	// +optional
	RenewDeadline string `json:"renewDeadline,omitempty"`

	// RetryPeriod is the duration the LeaderElector clients should wait
	// between tries of actions.
	//
	// Format: Go duration string (e.g., "5s")
	// Default: 5s (DefaultLeaderElectionRetryPeriod)
	// Must be less than RenewDeadline
	// +optional
	RetryPeriod string `json:"retryPeriod,omitempty"`
}

LeaderElectionConfig configures leader election for running multiple replicas.

func (*LeaderElectionConfig) DeepCopy

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LeaderElectionConfig.

func (*LeaderElectionConfig) DeepCopyInto

func (in *LeaderElectionConfig) DeepCopyInto(out *LeaderElectionConfig)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type LoggingConfig

type LoggingConfig struct {
	// Level controls the log level.
	//
	// Values: TRACE, DEBUG, INFO, WARN, ERROR (case-insensitive)
	//
	// If not set, the LOG_LEVEL environment variable is used.
	// If neither is set, defaults to INFO.
	// +kubebuilder:validation:Enum=TRACE;DEBUG;INFO;WARN;ERROR;trace;debug;info;warn;error;""
	// +optional
	Level string `json:"level,omitempty"`
}

LoggingConfig configures logging behavior.

func (*LoggingConfig) DeepCopy

func (in *LoggingConfig) DeepCopy() *LoggingConfig

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoggingConfig.

func (*LoggingConfig) DeepCopyInto

func (in *LoggingConfig) DeepCopyInto(out *LoggingConfig)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type MapFile

type MapFile struct {
	// Template is the template for generating the map file content.
	//
	// The rendered output should be in HAProxy map file format (key-value pairs).
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Template string `json:"template"`

	// PostProcessing defines optional post-processors to apply after rendering.
	//
	// Post-processors run in the order specified and can transform the rendered output.
	// +optional
	PostProcessing []PostProcessorConfig `json:"postProcessing,omitempty"`
}

MapFile defines a HAProxy map file generated from a template.

IMPORTANT: This is a Kubernetes CRD type. When modifying this struct, you must also update:

  • The internal config type: pkg/core/config/types.go (MapFile)
  • The conversion logic: pkg/controller/conversion/converter.go (ConvertSpec function - maps section)

func (*MapFile) DeepCopy

func (in *MapFile) DeepCopy() *MapFile

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MapFile.

func (*MapFile) DeepCopyInto

func (in *MapFile) DeepCopyInto(out *MapFile)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type PodDeploymentStatus

type PodDeploymentStatus struct {
	// PodName is the name of the HAProxy pod.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	PodName string `json:"podName"`

	// Checksum of the configuration deployed to this pod.
	// +optional
	Checksum string `json:"checksum,omitempty"`

	// LastError contains the error message from the most recent failed sync attempt.
	//
	// This field is cleared when a sync succeeds. Combined with ConsecutiveErrors,
	// this helps identify persistent vs transient issues.
	// +optional
	LastError string `json:"lastError,omitempty"`

	// ConsecutiveErrors is the count of consecutive sync failures.
	//
	// This counter increments on each failure and resets to 0 on success.
	// High values indicate persistent problems requiring investigation.
	// +optional
	// +kubebuilder:validation:Minimum=0
	ConsecutiveErrors int `json:"consecutiveErrors,omitempty"`
}

PodDeploymentStatus tracks deployment to a specific pod.

func (*PodDeploymentStatus) DeepCopy

func (in *PodDeploymentStatus) DeepCopy() *PodDeploymentStatus

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodDeploymentStatus.

func (*PodDeploymentStatus) DeepCopyInto

func (in *PodDeploymentStatus) DeepCopyInto(out *PodDeploymentStatus)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type PodSelector

type PodSelector struct {
	// MatchLabels are the labels to match HAProxy pods.
	//
	// Example:
	//   app: haproxy
	//   component: loadbalancer
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinProperties=1
	MatchLabels map[string]string `json:"matchLabels"`
}

PodSelector identifies which HAProxy pods to configure.

func (*PodSelector) DeepCopy

func (in *PodSelector) DeepCopy() *PodSelector

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodSelector.

func (*PodSelector) DeepCopyInto

func (in *PodSelector) DeepCopyInto(out *PodSelector)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type PostProcessorConfig

type PostProcessorConfig struct {
	// Type specifies the post-processor type (e.g., "regex_replace").
	// +kubebuilder:validation:Required
	Type string `json:"type"`

	// Params contains post-processor-specific parameters.
	//
	// For "regex_replace":
	//   - pattern: Regular expression pattern to match
	//   - replace: Replacement string
	// +kubebuilder:validation:Required
	Params map[string]string `json:"params"`
}

PostProcessorConfig defines a post-processor to apply to rendered template output.

IMPORTANT: This is a Kubernetes CRD type. When modifying this struct, you must also update:

  • The internal config type: pkg/core/config/types.go (PostProcessorConfig)
  • The conversion logic: pkg/controller/conversion/converter.go (ConvertSpec function)

func (*PostProcessorConfig) DeepCopy

func (in *PostProcessorConfig) DeepCopy() *PostProcessorConfig

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PostProcessorConfig.

func (*PostProcessorConfig) DeepCopyInto

func (in *PostProcessorConfig) DeepCopyInto(out *PostProcessorConfig)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ResourceReference

type ResourceReference struct {
	// Kind is the resource type (e.g., HAProxyMapFile, Secret).
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Kind string `json:"kind"`

	// Name is the resource name.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Name string `json:"name"`

	// Namespace is the resource namespace.
	// +optional
	Namespace string `json:"namespace,omitempty"`
}

ResourceReference identifies a related Kubernetes resource.

func (*ResourceReference) DeepCopy

func (in *ResourceReference) DeepCopy() *ResourceReference

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceReference.

func (*ResourceReference) DeepCopyInto

func (in *ResourceReference) DeepCopyInto(out *ResourceReference)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SSLCertificate

type SSLCertificate struct {
	// Template is the template for generating the certificate content.
	//
	// The rendered output should be in PEM format (certificate + private key).
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Template string `json:"template"`

	// PostProcessing defines optional post-processors to apply after rendering.
	//
	// Post-processors run in the order specified and can transform the rendered output.
	// +optional
	PostProcessing []PostProcessorConfig `json:"postProcessing,omitempty"`
}

SSLCertificate defines an SSL certificate generated from a template.

IMPORTANT: This is a Kubernetes CRD type. When modifying this struct, you must also update:

  • The internal config type: pkg/core/config/types.go (SSLCertificate)
  • The conversion logic: pkg/controller/conversion/converter.go (ConvertSpec function - sslCertificates section)

func (*SSLCertificate) DeepCopy

func (in *SSLCertificate) DeepCopy() *SSLCertificate

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SSLCertificate.

func (*SSLCertificate) DeepCopyInto

func (in *SSLCertificate) DeepCopyInto(out *SSLCertificate)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type SecretReference

type SecretReference struct {
	// Name is the name of the Secret.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Name string `json:"name"`

	// Namespace is the namespace of the Secret.
	//
	// If empty, defaults to the same namespace as the HAProxyTemplateConfig.
	// +optional
	Namespace string `json:"namespace,omitempty"`
}

SecretReference references a Secret by name and optional namespace.

func (*SecretReference) DeepCopy

func (in *SecretReference) DeepCopy() *SecretReference

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretReference.

func (*SecretReference) DeepCopyInto

func (in *SecretReference) DeepCopyInto(out *SecretReference)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type TemplateSnippet

type TemplateSnippet struct {
	// Template is the template content.
	//
	// Can be included in other templates using {{ render "snippet_name" }}.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Template string `json:"template"`

	// Requires lists watched-resource names this snippet depends on. When an
	// optional watched resource has no served candidate version, every
	// snippet requiring it is stripped from the effective config at load
	// time. Each entry must name a key of watchedResources.
	// +optional
	Requires []string `json:"requires,omitempty"`
}

TemplateSnippet defines a reusable template fragment.

func (*TemplateSnippet) DeepCopy

func (in *TemplateSnippet) DeepCopy() *TemplateSnippet

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplateSnippet.

func (*TemplateSnippet) DeepCopyInto

func (in *TemplateSnippet) DeepCopyInto(out *TemplateSnippet)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type TemplatingSettings

type TemplatingSettings struct {
	// Engine specifies which template engine to use for rendering.
	//
	// Available engines:
	//   - "scriggo" (default): Go template syntax, high performance rendering
	//
	// Default: scriggo
	// +kubebuilder:validation:Enum=scriggo
	// +optional
	Engine string `json:"engine,omitempty"`

	// ExtraContext provides custom variables that are passed to all templates.
	//
	// This allows users to add arbitrary data to the template context without
	// modifying controller code. Values can be any valid JSON type (string, number,
	// boolean, object, array).
	//
	// Example:
	//   extraContext:
	//     debug:
	//       enabled: true
	//     environment: production
	//     customValue: 42
	//
	// Templates can then reference these as: {{ debug.enabled }}, {{ environment }}, etc.
	// +optional
	// +kubebuilder:validation:Type=object
	// +kubebuilder:pruning:PreserveUnknownFields
	ExtraContext runtime.RawExtension `json:"extraContext,omitempty"`
}

TemplatingSettings configures template rendering behavior.

func (*TemplatingSettings) DeepCopy

func (in *TemplatingSettings) DeepCopy() *TemplatingSettings

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TemplatingSettings.

func (*TemplatingSettings) DeepCopyInto

func (in *TemplatingSettings) DeepCopyInto(out *TemplatingSettings)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ValidationAssertion

type ValidationAssertion struct {
	// Type is the assertion type.
	//
	// Supported types:
	//   - haproxy_valid: Validates that generated HAProxy config is syntactically valid
	//   - contains: Checks if target contains pattern (regex)
	//   - not_contains: Checks if target does not contain pattern (regex)
	//   - equals: Checks if target equals expected value
	//   - jsonpath: Evaluates JSONPath expression against target
	//   - match_count: Counts how many times pattern matches in target (regex)
	//   - match_order: Validates that patterns appear in specified order
	//   - deterministic: Verifies that rendering twice produces identical output
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:Enum=haproxy_valid;contains;not_contains;equals;jsonpath;match_count;match_order;deterministic
	Type string `json:"type"`

	// Description explains what this assertion validates.
	// +optional
	Description string `json:"description,omitempty"`

	// Target specifies what to validate.
	//
	// Format depends on assertion type:
	//   - haproxy_valid: not used
	//   - contains/not_contains/equals: "haproxy.cfg", "map:<name>", "file:<name>", "cert:<name>"
	//   - jsonpath: the resource to query
	// +optional
	Target string `json:"target,omitempty"`

	// Pattern is the regex pattern for contains/not_contains assertions.
	// +optional
	Pattern string `json:"pattern,omitempty"`

	// Expected is the expected value for equals assertions.
	// +optional
	Expected string `json:"expected,omitempty"`

	// JSONPath is the JSONPath expression for jsonpath assertions.
	// +optional
	JSONPath string `json:"jsonpath,omitempty"`

	// Patterns is a list of regex patterns for match_order assertions.
	// The patterns must appear in the target in the order specified.
	// +optional
	Patterns []string `json:"patterns,omitempty"`
}

ValidationAssertion defines a single validation check.

func (*ValidationAssertion) DeepCopy

func (in *ValidationAssertion) DeepCopy() *ValidationAssertion

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ValidationAssertion.

func (*ValidationAssertion) DeepCopyInto

func (in *ValidationAssertion) DeepCopyInto(out *ValidationAssertion)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ValidationTest

type ValidationTest struct {
	// Description explains what this test validates.
	// +optional
	Description string `json:"description,omitempty"`

	// Fixtures defines the Kubernetes resources to use for this test.
	//
	// Keys are resource type names (matching WatchedResources keys).
	// Values are arrays of resources as raw JSON.
	//
	// Example:
	//   ingresses:
	//     - apiVersion: networking.k8s.io/v1
	//       kind: Ingress
	//       metadata:
	//         name: test-ingress
	// +kubebuilder:validation:Required
	// +kubebuilder:pruning:PreserveUnknownFields
	Fixtures map[string][]runtime.RawExtension `json:"fixtures"`

	// HTTPResources defines mock HTTP content for this test.
	//
	// These fixtures are used when templates call http.Fetch() to provide
	// pre-defined content without making actual HTTP requests.
	//
	// Example:
	//   httpResources:
	//     - url: http://blocklist.example.com/list.txt
	//       content: |
	//         blocked-value-1
	//         blocked-value-2
	// +optional
	HTTPResources []HTTPResourceFixture `json:"httpResources,omitempty"`

	// CurrentConfig contains the raw HAProxy configuration from a previous deployment.
	//
	// This is used for testing slot-aware server assignment during rolling deployments.
	// When provided, templates can access currentConfig to preserve server slot ordering.
	// The content is parsed using the HAProxy config parser before being passed to templates.
	//
	// Example:
	//   currentConfig: |
	//     backend my-backend
	//         server srv1 10.0.0.1:8080
	//         server srv2 10.0.0.2:8080
	// +optional
	CurrentConfig string `json:"currentConfig,omitempty"`

	// ExtraContext provides custom variables that override the global extraContext for this test.
	//
	// This allows testing template behavior with different extraContext values without
	// modifying the global configuration.
	//
	// Example:
	//   extraContext:
	//     sanitize_auth_realm: true
	//     debug: true
	// +optional
	// +kubebuilder:validation:Type=object
	// +kubebuilder:pruning:PreserveUnknownFields
	ExtraContext runtime.RawExtension `json:"extraContext,omitempty"`

	// MinHAProxyVersion specifies the minimum HAProxy version required to run this test.
	//
	// When set, the test is skipped if the local HAProxy version is below this threshold.
	// This is useful for tests that use HAProxy features only available in newer versions
	// (e.g., shm-stats-file requires HAProxy 3.3+).
	//
	// Format: "major.minor" (e.g., "3.3")
	// +optional
	MinHAProxyVersion string `json:"minHAProxyVersion,omitempty"`

	// Requires lists watched-resource names this test depends on. When an
	// optional watched resource has no served candidate version, every test
	// requiring it is stripped from the effective config at load time.
	// Each entry must name a key of watchedResources.
	// +optional
	Requires []string `json:"requires,omitempty"`

	// RequiresFields lists schema field paths this test depends on, each in
	// the form "<watchedResourceKey>.<field.path>" (e.g.
	// "httproutes.spec.rules.filters.cors"). When any referenced field is
	// absent from the resolved schema generation of its watched resource,
	// the test is stripped from the effective config at load time. This
	// covers clusters that serve the resource at the same API version as
	// newer releases but with an older schema generation lacking the field.
	// The first dot-segment of each entry must name a key of
	// watchedResources.
	// +optional
	RequiresFields []string `json:"requiresFields,omitempty"`

	// Assertions defines the validation checks to perform.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinItems=1
	Assertions []ValidationAssertion `json:"assertions"`
}

ValidationTest defines a validation test with fixtures and assertions.

The test name is provided by the map key in ValidationTests.

func (*ValidationTest) DeepCopy

func (in *ValidationTest) DeepCopy() *ValidationTest

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ValidationTest.

func (*ValidationTest) DeepCopyInto

func (in *ValidationTest) DeepCopyInto(out *ValidationTest)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type ValidatorConfig

type ValidatorConfig struct {
	// Name is the operator-facing identifier for this validator.
	//
	// MUST be a valid RFC 1123 label (lowercase alphanumeric and `-`,
	// 1-63 characters). MUST be unique across the validators array.
	// Surfaces in admission denial messages so operators can identify
	// which validator rejected a change.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	// +kubebuilder:validation:MaxLength=63
	// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?$`
	Name string `json:"name"`

	// SocketPath is the absolute filesystem path to the validator's
	// Unix domain socket inside the controller pod.
	//
	// The chart-rendered shared `emptyDir` volume mounts at
	// `/var/run/haptic-validators/`; the conventional path is
	// `/var/run/haptic-validators/<name>.sock`. Custom paths must
	// still resolve inside the controller pod's filesystem.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	// +kubebuilder:validation:Pattern=`^/`
	SocketPath string `json:"socketPath"`

	// Files is a list of glob patterns matched against rendered file
	// paths to decide which files to send to this validator.
	//
	// Glob syntax follows Go's `path/filepath.Match` rules:
	//   - `*` matches any run of non-`/` characters.
	//   - `?` matches any single non-`/` character.
	//   - `[a-z]` matches any character in the range.
	//   - `**` is NOT supported; use multiple entries to cover
	//     directory hierarchies.
	//
	// At least one glob MUST be specified. Each glob MUST be an
	// absolute path (start with `/`) so it matches the rendered file
	// paths that the controller produces (e.g. `/etc/haproxy/maps/host.map`,
	// `/etc/haproxy-spoa-hub/config.toml`). Operators get the matching
	// behaviour they expect from a path-style glob.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinItems=1
	// +listType=set
	Files []string `json:"files"`

	// TimeoutMs is the per-call deadline, in milliseconds, covering
	// the request-response cycle for one file (connect-or-acquire +
	// write + read).
	//
	// Defaults to 5000 (5 seconds) when omitted. Validator calls
	// exceeding this deadline are surfaced as `result: "error"` so a
	// wedged sidecar does not stall the webhook path indefinitely.
	// +optional
	// +kubebuilder:validation:Minimum=1
	// +kubebuilder:validation:Maximum=60000
	TimeoutMs *int32 `json:"timeoutMs,omitempty"`

	// MaxConnections caps the size of the controller's connection
	// pool to this validator's socket. The pool starts small (one
	// idle connection) and grows on contention up to this cap;
	// connections idle past the validator's idle timeout are reaped
	// transparently and reopened on next use.
	//
	// Defaults to 4 when omitted. Setting 1 reproduces a serial
	// client (one validation in flight at a time). Higher values
	// allow more concurrent validations during reconciliation bursts
	// at the cost of file descriptors and validator-side resource
	// pressure.
	// +optional
	// +kubebuilder:validation:Minimum=1
	// +kubebuilder:validation:Maximum=32
	MaxConnections *int32 `json:"maxConnections,omitempty"`
}

ValidatorConfig declares one pluggable validator sidecar that the controller will consult during admission webhook processing.

The wire protocol between the controller and a validator sidecar is documented in `docs/development/validator-protocol.md` and is owned by HAPTIC. Reference implementation: `haproxy-spoa-hub --validate-socket <path>` shipped alongside HAPTIC; any conforming implementation may be substituted. The validator program is opaque to HAPTIC — its internal architecture (whether it has plugins, how it dispatches files, how it parses content) is its own concern.

Operators declare zero, one, or many validators. Each one runs in its own sidecar container in the controller pod and shares a Unix domain socket via an emptyDir volume; the chart wires this up automatically when `spec.validators` is non-empty.

Routing: HAPTIC matches each rendered file's path against every validator's `files` glob list. Files that match are sent to that validator over its socket. A file that matches multiple validators' globs is sent to each of them. Files that match no validator's globs are not validated by any sidecar (they still flow through the existing template + HAProxy syntax dry-run).

func (*ValidatorConfig) DeepCopy

func (in *ValidatorConfig) DeepCopy() *ValidatorConfig

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ValidatorConfig.

func (*ValidatorConfig) DeepCopyInto

func (in *ValidatorConfig) DeepCopyInto(out *ValidatorConfig)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

type WatchedResource

type WatchedResource struct {
	// APIVersion is the Kubernetes API version (e.g., "networking.k8s.io/v1").
	//
	// Mutually exclusive with apiVersions (exactly one must be set; the
	// controller's config validation enforces this). Equivalent to a
	// one-element apiVersions list.
	// +optional
	APIVersion string `json:"apiVersion,omitempty"`

	// APIVersions is an ordered candidate list of API versions. The
	// controller resolves the entry to the FIRST candidate the apiserver
	// serves and watches that version. Mutually exclusive with apiVersion.
	//
	// Example: ["gateway.networking.k8s.io/v1", "gateway.networking.k8s.io/v1beta1"]
	// +optional
	// +kubebuilder:validation:MinItems=1
	APIVersions []string `json:"apiVersions,omitempty"`

	// Optional marks this resource as non-essential: when NO candidate
	// version is served by the cluster, the watch is dropped and every
	// templateSnippet / validationTest whose requires list names this
	// resource is stripped from the effective config at load time, instead
	// of failing startup.
	// +optional
	Optional bool `json:"optional,omitempty"`

	// Resources is the plural form of the Kubernetes resource type (e.g., "ingresses", "services").
	//
	// This is the name used in RBAC rules and API paths.
	// +kubebuilder:validation:Required
	// +kubebuilder:validation:MinLength=1
	Resources string `json:"resources"`

	// EnableValidationWebhook enables admission webhook validation for this resource.
	//
	// When enabled, the controller will validate resources of this type before they're saved.
	// Default: false
	// +optional
	EnableValidationWebhook bool `json:"enableValidationWebhook,omitempty"`

	// IndexBy specifies JSONPath expressions for extracting index keys.
	//
	// Resources are indexed by these values for O(1) lookup in templates.
	//
	// Examples:
	//   - ["metadata.namespace", "metadata.name"]
	//   - ["metadata.labels['kubernetes.io/service-name']"]
	// +optional
	IndexBy []string `json:"indexBy,omitempty"`

	// LabelSelector filters resources by labels (server-side filtering).
	//
	// Equality-only: comma-separated "key=value" pairs.
	// Example: "app=nginx,environment=production"
	// Set-based syntax (e.g. "tier in (frontend,api)", "!disabled") is NOT supported —
	// the controller's parseLabelSelector splits on ',' and '=' and silently drops the rest.
	// +optional
	LabelSelector string `json:"labelSelector,omitempty"`

	// FieldSelector filters resources using client-side JSONPath evaluation.
	// Unlike Kubernetes' native fieldSelector (which only supports limited fields),
	// this supports any JSONPath expression.
	//
	// Format: "field.path=value"
	// Example: "spec.ingressClassName=haproxy-internal"
	// +optional
	FieldSelector string `json:"fieldSelector,omitempty"`

	// Store specifies the storage backend for this resource type.
	//
	// Valid values:
	//   - "full": MemoryStore - keeps all resources in memory (faster, higher memory usage)
	//   - "on-demand": CachedStore - fetches resources on-demand with caching (slower, lower memory usage)
	//
	// Default: "full"
	//
	// Use "on-demand" for large resources accessed infrequently (e.g., Secrets).
	// Use "full" for frequently accessed resources (e.g., Ingress, Service, EndpointSlice).
	// +kubebuilder:validation:Enum=full;on-demand
	// +optional
	Store string `json:"store,omitempty"`

	// DebounceInterval overrides the watcher's refractory window.
	// "0" disables debouncing; default 2s.
	// +optional
	DebounceInterval string `json:"debounceInterval,omitempty"`
}

WatchedResource configures watching for a specific Kubernetes resource type.

func (*WatchedResource) DeepCopy

func (in *WatchedResource) DeepCopy() *WatchedResource

DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WatchedResource.

func (*WatchedResource) DeepCopyInto

func (in *WatchedResource) DeepCopyInto(out *WatchedResource)

DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.

Jump to

Keyboard shortcuts

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