package v1

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/runtime"

	corev1 "k8s.io/api/core/v1"

	configv1 "github.com/openshift/api/config/v1"
)

// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:subresource:scale:specpath=.spec.replicas,statuspath=.status.availableReplicas,selectorpath=.status.selector
// +kubebuilder:resource:path=ingresscontrollers,scope=Namespaced
// +openshift:api-approved.openshift.io=https://github.com/openshift/api/pull/616
// +openshift:capability=Ingress
// +openshift:file-pattern=cvoRunLevel=0000_50,operatorName=ingress,operatorOrdering=00

// IngressController describes a managed ingress controller for the cluster. The
// controller can service OpenShift Route and Kubernetes Ingress resources.
//
// When an IngressController is created, a new ingress controller deployment is
// created to allow external traffic to reach the services that expose Ingress
// or Route resources. Updating this resource may lead to disruption for public
// facing network connections as a new ingress controller revision may be rolled
// out.
//
// https://kubernetes.io/docs/concepts/services-networking/ingress-controllers
//
// Whenever possible, sensible defaults for the platform are used. See each
// field for more details.
//
// Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).
// +openshift:compatibility-gen:level=1
// +kubebuilder:validation:XValidation:rule="!has(self.spec.domain) || size('router-' + self.metadata.name + '.' + self.spec.domain) <= 253",message="The combined 'router-' + metadata.name + '.' + .spec.domain cannot exceed 253 characters"
type IngressController struct {
	metav1.TypeMeta `json:",inline"`

	// metadata is the standard object's metadata.
	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
	metav1.ObjectMeta `json:"metadata,omitempty"`

	// spec is the specification of the desired behavior of the IngressController.
	Spec IngressControllerSpec `json:"spec,omitempty"`
	// status is the most recently observed status of the IngressController.
	Status IngressControllerStatus `json:"status,omitempty"`
}

// IngressControllerSpec is the specification of the desired behavior of the
// IngressController.
type IngressControllerSpec struct {
	// domain is a DNS name serviced by the ingress controller and is used to
	// configure multiple features:
	//
	// * For the LoadBalancerService endpoint publishing strategy, domain is
	//   used to configure DNS records. See endpointPublishingStrategy.
	//
	// * When using a generated default certificate, the certificate will be valid
	//   for domain and its subdomains. See defaultCertificate.
	//
	// * The value is published to individual Route statuses so that end-users
	//   know where to target external DNS records.
	//
	// domain must be unique among all IngressControllers, and cannot be
	// updated.
	//
	// If empty, defaults to ingress.config.openshift.io/cluster .spec.domain.
	//
	// The domain value must be a valid DNS name. It must consist of lowercase
	// alphanumeric characters, '-' or '.', and each label must start and end
	// with an alphanumeric character and not exceed 63 characters. Maximum
	// length of a valid DNS domain is 253 characters.
	//
	// The implementation may add a prefix such as "router-default." to the domain
	// when constructing the router canonical hostname. To ensure the resulting
	// hostname does not exceed the DNS maximum length of 253 characters,
	// the domain length is additionally validated at the IngressController object
	// level. For the maximum length of the domain value itself, the shortest
	// possible variant of the prefix and the ingress controller name was considered
	// for example "router-a."
	//
	// +kubebuilder:validation:MaxLength=244
	// +kubebuilder:validation:XValidation:rule="!format.dns1123Subdomain().validate(self).hasValue()",message="domain must consist of lower case alphanumeric characters, '-' or '.', and must start and end with an alphanumeric character"
	// +kubebuilder:validation:XValidation:rule="self.split('.').all(label, size(label) <= 63)",message="each DNS label must not exceed 63 characters"
	// +optional
	Domain string `json:"domain,omitempty"`

	// httpErrorCodePages specifies a configmap with custom error pages.
	// The administrator must create this configmap in the openshift-config namespace.
	// This configmap should have keys in the format "error-page-<error code>.http",
	// where <error code> is an HTTP error code.
	// For example, "error-page-503.http" defines an error page for HTTP 503 responses.
	// Currently only error pages for 503 and 404 responses can be customized.
	// Each value in the configmap should be the full response, including HTTP headers.
	// Eg- https://raw.githubusercontent.com/openshift/router/fadab45747a9b30cc3f0a4b41ad2871f95827a93/images/router/haproxy/conf/error-page-503.http
	// If this field is empty, the ingress controller uses the default error pages.
	HttpErrorCodePages configv1.ConfigMapNameReference `json:"httpErrorCodePages,omitempty"`

	// replicas is the desired number of ingress controller replicas. If unset,
	// the default depends on the value of the defaultPlacement field in the
	// cluster config.openshift.io/v1/ingresses status.
	//
	// The value of replicas is set based on the value of a chosen field in the
	// Infrastructure CR. If defaultPlacement is set to ControlPlane, the
	// chosen field will be controlPlaneTopology. If it is set to Workers the
	// chosen field will be infrastructureTopology. Replicas will then be set to 1
	// or 2 based whether the chosen field's value is SingleReplica or
	// HighlyAvailable, respectively.
	//
	// These defaults are subject to change.
	//
	// +optional
	Replicas *int32 `json:"replicas,omitempty"`

	// endpointPublishingStrategy is used to publish the ingress controller
	// endpoints to other networks, enable load balancer integrations, etc.
	//
	// If unset, the default is based on
	// infrastructure.config.openshift.io/cluster .status.platform:
	//
	//   AWS:          LoadBalancerService (with External scope)
	//   Azure:        LoadBalancerService (with External scope)
	//   GCP:          LoadBalancerService (with External scope)
	//   IBMCloud:     LoadBalancerService (with External scope)
	//   AlibabaCloud: LoadBalancerService (with External scope)
	//   Libvirt:      HostNetwork
	//
	// Any other platform types (including None) default to HostNetwork.
	//
	// endpointPublishingStrategy cannot be updated.
	//
	// +optional
	EndpointPublishingStrategy *EndpointPublishingStrategy `json:"endpointPublishingStrategy,omitempty"`

	// defaultCertificate is a reference to a secret containing the default
	// certificate served by the ingress controller. When Routes don't specify
	// their own certificate, defaultCertificate is used.
	//
	// The secret must contain the following keys and data:
	//
	//   tls.crt: certificate file contents
	//   tls.key: key file contents
	//
	// If unset, a wildcard certificate is automatically generated and used. The
	// certificate is valid for the ingress controller domain (and subdomains) and
	// the generated certificate's CA will be automatically integrated with the
	// cluster's trust store.
	//
	// If a wildcard certificate is used and shared by multiple
	// HTTP/2 enabled routes (which implies ALPN) then clients
	// (i.e., notably browsers) are at liberty to reuse open
	// connections. This means a client can reuse a connection to
	// another route and that is likely to fail. This behaviour is
	// generally known as connection coalescing.
	//
	// The in-use certificate (whether generated or user-specified) will be
	// automatically integrated with OpenShift's built-in OAuth server.
	//
	// +optional
	DefaultCertificate *corev1.LocalObjectReference `json:"defaultCertificate,omitempty"`

	// namespaceSelector is used to filter the set of namespaces serviced by the
	// ingress controller. This is useful for implementing shards.
	//
	// If unset, the default is no filtering.
	//
	// +optional
	NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"`

	// routeSelector is used to filter the set of Routes serviced by the ingress
	// controller. This is useful for implementing shards.
	//
	// If unset, the default is no filtering.
	//
	// +optional
	RouteSelector *metav1.LabelSelector `json:"routeSelector,omitempty"`

	// nodePlacement enables explicit control over the scheduling of the ingress
	// controller.
	//
	// If unset, defaults are used. See NodePlacement for more details.
	//
	// +optional
	NodePlacement *NodePlacement `json:"nodePlacement,omitempty"`

	// tlsSecurityProfile specifies settings for TLS connections for ingresscontrollers.
	//
	// If unset, the default is based on the apiservers.config.openshift.io/cluster resource.
	//
	// Note that when using the Old, Intermediate, and Modern profile types, the effective
	// profile configuration is subject to change between releases. For example, given
	// a specification to use the Intermediate profile deployed on release X.Y.Z, an upgrade
	// to release X.Y.Z+1 may cause a new profile configuration to be applied to the ingress
	// controller, resulting in a rollout.
	//
	// +optional
	TLSSecurityProfile *configv1.TLSSecurityProfile `json:"tlsSecurityProfile,omitempty"`

	// clientTLS specifies settings for requesting and verifying client
	// certificates, which can be used to enable mutual TLS for
	// edge-terminated and reencrypt routes.
	//
	// +optional
	ClientTLS ClientTLS `json:"clientTLS"`

	// routeAdmission defines a policy for handling new route claims (for example,
	// to allow or deny claims across namespaces).
	//
	// If empty, defaults will be applied. See specific routeAdmission fields
	// for details about their defaults.
	//
	// +optional
	RouteAdmission *RouteAdmissionPolicy `json:"routeAdmission,omitempty"`

	// logging defines parameters for what should be logged where.  If this
	// field is empty, operational logs are enabled but access logs are
	// disabled.
	//
	// +optional
	Logging *IngressControllerLogging `json:"logging,omitempty"`

	// httpHeaders defines policy for HTTP headers.
	//
	// If this field is empty, the default values are used.
	//
	// +optional
	HTTPHeaders *IngressControllerHTTPHeaders `json:"httpHeaders,omitempty"`

	// httpEmptyRequestsPolicy describes how HTTP connections should be
	// handled if the connection times out before a request is received.
	// Allowed values for this field are "Respond" and "Ignore".  If the
	// field is set to "Respond", the ingress controller sends an HTTP 400
	// or 408 response, logs the connection (if access logging is enabled),
	// and counts the connection in the appropriate metrics.  If the field
	// is set to "Ignore", the ingress controller closes the connection
	// without sending a response, logging the connection, or incrementing
	// metrics.  The default value is "Respond".
	//
	// Typically, these connections come from load balancers' health probes
	// or Web browsers' speculative connections ("preconnect") and can be
	// safely ignored.  However, these requests may also be caused by
	// network errors, and so setting this field to "Ignore" may impede
	// detection and diagnosis of problems.  In addition, these requests may
	// be caused by port scans, in which case logging empty requests may aid
	// in detecting intrusion attempts.
	//
	// +optional
	// +kubebuilder:default:="Respond"
	HTTPEmptyRequestsPolicy HTTPEmptyRequestsPolicy `json:"httpEmptyRequestsPolicy,omitempty"`

	// tuningOptions defines parameters for adjusting the performance of
	// ingress controller pods. All fields are optional and will use their
	// respective defaults if not set. See specific tuningOptions fields for
	// more details.
	//
	// Setting fields within tuningOptions is generally not recommended. The
	// default values are suitable for most configurations.
	//
	// +optional
	TuningOptions IngressControllerTuningOptions `json:"tuningOptions,omitempty"`

	// unsupportedConfigOverrides allows specifying unsupported
	// configuration options.  Its use is unsupported.
	//
	// +optional
	// +nullable
	// +kubebuilder:pruning:PreserveUnknownFields
	UnsupportedConfigOverrides runtime.RawExtension `json:"unsupportedConfigOverrides"`

	// httpCompression defines a policy for HTTP traffic compression.
	// By default, there is no HTTP compression.
	//
	// +optional
	HTTPCompression HTTPCompressionPolicy `json:"httpCompression,omitempty"`

	// idleConnectionTerminationPolicy maps directly to HAProxy's
	// idle-close-on-response option and controls whether HAProxy
	// keeps idle frontend connections open during a soft stop
	// (router reload).
	//
	// Allowed values for this field are "Immediate" and
	// "Deferred". The default value is "Immediate".
	//
	// When set to "Immediate", idle connections are closed
	// immediately during router reloads. This ensures immediate
	// propagation of route changes but may impact clients
	// sensitive to connection resets.
	//
	// When set to "Deferred", HAProxy will maintain idle
	// connections during a soft reload instead of closing them
	// immediately. These connections remain open until any of the
	// following occurs:
	//
	//   - A new request is received on the connection, in which
	//     case HAProxy handles it in the old process and closes
	//     the connection after sending the response.
	//
	//   - HAProxy's `timeout http-keep-alive` duration expires.
	//     By default this is 300 seconds, but it can be changed
	//     using httpKeepAliveTimeout tuning option.
	//
	//   - The client's keep-alive timeout expires, causing the
	//     client to close the connection.
	//
	// Setting Deferred can help prevent errors in clients or load
	// balancers that do not properly handle connection resets.
	// Additionally, this option allows you to retain the pre-2.4
	// HAProxy behaviour: in HAProxy version 2.2 (OpenShift
	// versions < 4.14), maintaining idle connections during a
	// soft reload was the default behaviour, but starting with
	// HAProxy 2.4, the default changed to closing idle
	// connections immediately.
	//
	// Important Consideration:
	//
	//   - Using Deferred will result in temporary inconsistencies
	//     for the first request on each persistent connection
	//     after a route update and router reload. This request
	//     will be processed by the old HAProxy process using its
	//     old configuration. Subsequent requests will use the
	//     updated configuration.
	//
	// Operational Considerations:
	//
	//   - Keeping idle connections open during reloads may lead
	//     to an accumulation of old HAProxy processes if
	//     connections remain idle for extended periods,
	//     especially in environments where frequent reloads
	//     occur.
	//
	//   - Consider monitoring the number of HAProxy processes in
	//     the router pods when Deferred is set.
	//
	//   - You may need to enable or adjust the
	//     `ingress.operator.openshift.io/hard-stop-after`
	//     duration (configured via an annotation on the
	//     IngressController resource) in environments with
	//     frequent reloads to prevent resource exhaustion.
	//
	// +optional
	// +kubebuilder:default:="Immediate"
	// +default="Immediate"
	IdleConnectionTerminationPolicy IngressControllerConnectionTerminationPolicy `json:"idleConnectionTerminationPolicy,omitempty"`

	// closedClientConnectionPolicy controls how the IngressController
	// behaves when the client closes the TCP connection while the TLS
	// handshake or HTTP request is in progress. This option maps directly
	// to HAProxy’s "abortonclose" option.
	//
	// Valid values are: "Abort" and "Continue".
	// The default value is "Continue".
	//
	// When set to "Abort", the router will stop processing the TLS handshake
	// if it is in progress, and it will not send an HTTP request to the backend server
	// if the request has not yet been sent when the client closes the connection.
	//
	// When set to "Continue", the router will complete the TLS handshake
	// if it is in progress, or send an HTTP request to the backend server
	// and wait for the backend server's response, regardless of
	// whether the client has closed the connection.
	//
	// Setting "Abort" can help free CPU resources otherwise spent on TLS computation
	// for connections the client has already closed, and can reduce request queue
	// size, thereby reducing the load on saturated backend servers.
	//
	// Important Considerations:
	//
	//   - The default policy ("Continue") is HTTP-compliant, and requests
	//     for aborted client connections will still be served.
	//     Use the "Continue" policy to allow a client to send a request
	//     and then immediately close its side of the connection while
	//     still receiving a response on the half-closed connection.
	//
	//   - When clients use keep-alive connections, the most common case for premature
	//     closure is when the user wants to cancel the transfer or when a timeout
	//     occurs. In that case, the "Abort" policy may be used to reduce resource consumption.
	//
	//   - Using RSA keys larger than 2048 bits can significantly slow down
	//     TLS computations. Consider using the "Abort" policy to reduce CPU usage.
	//
	// +optional
	// +kubebuilder:default:="Continue"
	// +default="Continue"
	ClosedClientConnectionPolicy IngressControllerClosedClientConnectionPolicy `json:"closedClientConnectionPolicy,omitempty"`

	// haproxyVersion specifies the HAProxy version to use for this
	// IngressController.
	//
	// OpenShift 5.0 introduces HAProxy 3.2 as its default version and supports
	// HAProxy 2.8 from OpenShift 4.22 for migration purposes. When an OpenShift
	// release introduces a new default HAProxy version, that HAProxy version
	// becomes available as a pinnable value in subsequent OpenShift releases,
	// providing a smooth migration path for administrators who want to defer
	// HAProxy upgrades.
	//
	// Valid values for OpenShift 5.0:
	// - Unset (default): Uses HAProxy 3.2 (the default for OpenShift 5.0)
	// - "3.2": Explicitly pins HAProxy 3.2 for preservation during cluster
	//   upgrades to future OpenShift releases
	// - "2.8": Uses HAProxy 2.8 from OpenShift 4.22 (migration support, will
	//   be dropped in the next OpenShift release)
	//
	// If a specific HAProxy version is set and would become unsupported in a
	// target cluster upgrade, a preflight check will block the cluster upgrade
	// until this field is updated to unset or a supported version.
	//
	// +optional
	// +openshift:enable:FeatureGate=IngressControllerMultipleHAProxyVersions
	HAProxyVersion HAProxyVersion `json:"haproxyVersion,omitempty"`
}

// httpCompressionPolicy turns on compression for the specified MIME types.
//
// This field is optional, and its absence implies that compression should not be enabled
// globally in HAProxy.
//
// If httpCompressionPolicy exists, compression should be enabled only for the specified
// MIME types.
type HTTPCompressionPolicy struct {
	// mimeTypes is a list of MIME types that should have compression applied.
	// This list can be empty, in which case the ingress controller does not apply compression.
	//
	// Note: Not all MIME types benefit from compression, but HAProxy will still use resources
	// to try to compress if instructed to.  Generally speaking, text (html, css, js, etc.)
	// formats benefit from compression, but formats that are already compressed (image,
	// audio, video, etc.) benefit little in exchange for the time and cpu spent on compressing
	// again. See https://joehonton.medium.com/the-gzip-penalty-d31bd697f1a2
	//
	// +listType=set
	MimeTypes []CompressionMIMEType `json:"mimeTypes,omitempty"`
}

// CompressionMIMEType defines the format of a single MIME type.
// E.g. "text/css; charset=utf-8", "text/html", "text/*", "image/svg+xml",
// "application/octet-stream", "X-custom/customsub", etc.
//
// The format should follow the Content-Type definition in RFC 1341:
// Content-Type := type "/" subtype *[";" parameter]
//   - The type in Content-Type can be one of:
//     application, audio, image, message, multipart, text, video, or a custom
//     type preceded by "X-" and followed by a token as defined below.
//   - The token is a string of at least one character, and not containing white
//     space, control characters, or any of the characters in the tspecials set.
//   - The tspecials set contains the characters ()<>@,;:\"/[]?.=
//   - The subtype in Content-Type is also a token.
//   - The optional parameter/s following the subtype are defined as:
//     token "=" (token / quoted-string)
//   - The quoted-string, as defined in RFC 822, is surrounded by double quotes
//     and can contain white space plus any character EXCEPT \, ", and CR.
//     It can also contain any single ASCII character as long as it is escaped by \.
//
// +kubebuilder:validation:Pattern=`^(?i)(x-[^][ ()\\<>@,;:"/?.=\x00-\x1F\x7F]+|application|audio|image|message|multipart|text|video)/[^][ ()\\<>@,;:"/?.=\x00-\x1F\x7F]+(; *[^][ ()\\<>@,;:"/?.=\x00-\x1F\x7F]+=([^][ ()\\<>@,;:"/?.=\x00-\x1F\x7F]+|"(\\[\x00-\x7F]|[^\x0D"\\])*"))*$`
type CompressionMIMEType string

// NodePlacement describes node scheduling configuration for an ingress
// controller.
type NodePlacement struct {
	// nodeSelector is the node selector applied to ingress controller
	// deployments.
	//
	// If set, the specified selector is used and replaces the default.
	//
	// If unset, the default depends on the value of the defaultPlacement
	// field in the cluster config.openshift.io/v1/ingresses status.
	//
	// When defaultPlacement is Workers, the default is:
	//
	//   kubernetes.io/os: linux
	//   node-role.kubernetes.io/worker: ''
	//
	// When defaultPlacement is ControlPlane, the default is:
	//
	//   kubernetes.io/os: linux
	//   node-role.kubernetes.io/master: ''
	//
	// These defaults are subject to change.
	//
	// Note that using nodeSelector.matchExpressions is not supported.  Only
	// nodeSelector.matchLabels may be used.  This is a limitation of the
	// Kubernetes API: the pod spec does not allow complex expressions for
	// node selectors.
	//
	// +optional
	NodeSelector *metav1.LabelSelector `json:"nodeSelector,omitempty"`

	// tolerations is a list of tolerations applied to ingress controller
	// deployments.
	//
	// The default is an empty list.
	//
	// See https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
	//
	// +optional
	// +listType=atomic
	Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
}

// EndpointPublishingStrategyType is a way to publish ingress controller endpoints.
// +kubebuilder:validation:Enum=LoadBalancerService;HostNetwork;Private;NodePortService
type EndpointPublishingStrategyType string

const (
	// LoadBalancerService publishes the ingress controller using a Kubernetes
	// LoadBalancer Service.
	LoadBalancerServiceStrategyType EndpointPublishingStrategyType = "LoadBalancerService"

	// HostNetwork publishes the ingress controller on node ports where the
	// ingress controller is deployed.
	HostNetworkStrategyType EndpointPublishingStrategyType = "HostNetwork"

	// Private does not publish the ingress controller.
	PrivateStrategyType EndpointPublishingStrategyType = "Private"

	// NodePortService publishes the ingress controller using a Kubernetes NodePort Service.
	NodePortServiceStrategyType EndpointPublishingStrategyType = "NodePortService"
)

// LoadBalancerScope is the scope at which a load balancer is exposed.
// +kubebuilder:validation:Enum=Internal;External
type LoadBalancerScope string

var (
	// InternalLoadBalancer is a load balancer that is exposed only on the
	// cluster's private network.
	InternalLoadBalancer LoadBalancerScope = "Internal"

	// ExternalLoadBalancer is a load balancer that is exposed on the
	// cluster's public network (which is typically on the Internet).
	ExternalLoadBalancer LoadBalancerScope = "External"
)

// CIDR is an IP address range in CIDR notation (for example, "10.0.0.0/8"
// or "fd00::/8").
// +kubebuilder:validation:Pattern=`(^(([0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[0-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])/([0-9]|[12][0-9]|3[0-2])$)|(^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/(12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))$)`
// + ---
// + The regex for the IPv4 CIDR range was taken from other CIDR fields in the OpenShift API
// + and the one for the IPv6 CIDR range was taken from
// + https://blog.markhatton.co.uk/2011/03/15/regular-expressions-for-ip-addresses-cidr-ranges-and-hostnames/
// + The resulting regex is an OR of both regexes.
type CIDR string

// LoadBalancerStrategy holds parameters for a load balancer.
// +kubebuilder:validation:XValidation:rule="!has(self.scope) || self.scope != 'Internal' || !has(self.providerParameters) || !has(self.providerParameters.aws) || !has(self.providerParameters.aws.networkLoadBalancer) || !has(self.providerParameters.aws.networkLoadBalancer.eipAllocations)",message="eipAllocations are forbidden when the scope is Internal."
// +kubebuilder:validation:XValidation:rule=`!has(self.scope) || self.scope != 'Internal' || !has(self.providerParameters) || !has(self.providerParameters.openstack) || !has(self.providerParameters.openstack.floatingIP) || self.providerParameters.openstack.floatingIP == ""`,message="cannot specify a floating ip when scope is internal"
type LoadBalancerStrategy struct {
	// scope indicates the scope at which the load balancer is exposed.
	// Possible values are "External" and "Internal".
	//
	// +required
	Scope LoadBalancerScope `json:"scope"`

	// allowedSourceRanges specifies an allowlist of IP address ranges to which
	// access to the load balancer should be restricted.  Each range must be
	// specified using CIDR notation (e.g. "10.0.0.0/8" or "fd00::/8"). If no range is
	// specified, "0.0.0.0/0" for IPv4 and "::/0" for IPv6 are used by default,
	// which allows all source addresses.
	//
	// To facilitate migration from earlier versions of OpenShift that did
	// not have the allowedSourceRanges field, you may set the
	// service.beta.kubernetes.io/load-balancer-source-ranges annotation on
	// the "router-<ingresscontroller name>" service in the
	// "openshift-ingress" namespace, and this annotation will take
	// effect if allowedSourceRanges is empty on OpenShift 4.12.
	//
	// +nullable
	// +optional
	// +listType=atomic
	AllowedSourceRanges []CIDR `json:"allowedSourceRanges,omitempty"`

	// providerParameters holds desired load balancer information specific to
	// the underlying infrastructure provider.
	//
	// If empty, defaults will be applied. See specific providerParameters
	// fields for details about their defaults.
	//
	// +optional
	ProviderParameters *ProviderLoadBalancerParameters `json:"providerParameters,omitempty"`

	// dnsManagementPolicy indicates if the lifecycle of the wildcard DNS record
	// associated with the load balancer service will be managed by
	// the ingress operator. It defaults to Managed.
	// Valid values are: Managed and Unmanaged.
	//
	// +kubebuilder:default:="Managed"
	// +required
	// +default="Managed"
	DNSManagementPolicy LoadBalancerDNSManagementPolicy `json:"dnsManagementPolicy,omitempty"`
}

// LoadBalancerDNSManagementPolicy is a policy for configuring how
// ingresscontrollers manage DNS.
//
// +kubebuilder:validation:Enum=Managed;Unmanaged
type LoadBalancerDNSManagementPolicy string

const (
	// ManagedLoadBalancerDNS specifies that the operator manages
	// a wildcard DNS record for the ingresscontroller.
	ManagedLoadBalancerDNS LoadBalancerDNSManagementPolicy = "Managed"
	// UnmanagedLoadBalancerDNS specifies that the operator does not manage
	// any wildcard DNS record for the ingresscontroller.
	UnmanagedLoadBalancerDNS LoadBalancerDNSManagementPolicy = "Unmanaged"
)

// ProviderLoadBalancerParameters holds desired load balancer information
// specific to the underlying infrastructure provider.
// +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'OpenStack' ? true : !has(self.openstack)",message="openstack is not permitted when type is not OpenStack"
// +union
type ProviderLoadBalancerParameters struct {
	// type is the underlying infrastructure provider for the load balancer.
	// Allowed values are "AWS", "Azure", "BareMetal", "GCP", "IBM", "Nutanix",
	// "OpenStack", and "VSphere".
	//
	// +unionDiscriminator
	// +required
	Type LoadBalancerProviderType `json:"type"`

	// aws provides configuration settings that are specific to AWS
	// load balancers.
	//
	// If empty, defaults will be applied. See specific aws fields for
	// details about their defaults.
	//
	// +optional
	AWS *AWSLoadBalancerParameters `json:"aws,omitempty"`

	// gcp provides configuration settings that are specific to GCP
	// load balancers.
	//
	// If empty, defaults will be applied. See specific gcp fields for
	// details about their defaults.
	//
	// +optional
	GCP *GCPLoadBalancerParameters `json:"gcp,omitempty"`

	// ibm provides configuration settings that are specific to IBM Cloud
	// load balancers.
	//
	// If empty, defaults will be applied. See specific ibm fields for
	// details about their defaults.
	//
	// +optional
	IBM *IBMLoadBalancerParameters `json:"ibm,omitempty"`

	// openstack provides configuration settings that are specific to OpenStack
	// load balancers.
	//
	// If empty, defaults will be applied. See specific openstack fields for
	// details about their defaults.
	//
	// +optional
	OpenStack *OpenStackLoadBalancerParameters `json:"openstack,omitempty"`
}

// LoadBalancerProviderType is the underlying infrastructure provider for the
// load balancer. Allowed values are "AWS", "Azure", "BareMetal", "GCP", "IBM", "Nutanix",
// "OpenStack", and "VSphere".
//
// +kubebuilder:validation:Enum=AWS;Azure;BareMetal;GCP;Nutanix;OpenStack;VSphere;IBM
type LoadBalancerProviderType string

const (
	AWSLoadBalancerProvider          LoadBalancerProviderType = "AWS"
	AzureLoadBalancerProvider        LoadBalancerProviderType = "Azure"
	GCPLoadBalancerProvider          LoadBalancerProviderType = "GCP"
	OpenStackLoadBalancerProvider    LoadBalancerProviderType = "OpenStack"
	VSphereLoadBalancerProvider      LoadBalancerProviderType = "VSphere"
	IBMLoadBalancerProvider          LoadBalancerProviderType = "IBM"
	BareMetalLoadBalancerProvider    LoadBalancerProviderType = "BareMetal"
	AlibabaCloudLoadBalancerProvider LoadBalancerProviderType = "AlibabaCloud"
	NutanixLoadBalancerProvider      LoadBalancerProviderType = "Nutanix"
)

// AWSLoadBalancerParameters provides configuration settings that are
// specific to AWS load balancers.
// +union
type AWSLoadBalancerParameters struct {
	// type is the type of AWS load balancer to instantiate for an ingresscontroller.
	//
	// Valid values are:
	//
	// * "Classic": A Classic Load Balancer that makes routing decisions at either
	//   the transport layer (TCP/SSL) or the application layer (HTTP/HTTPS). See
	//   the following for additional details:
	//
	//     https://docs.aws.amazon.com/AmazonECS/latest/developerguide/load-balancer-types.html#clb
	//
	// * "NLB": A Network Load Balancer that makes routing decisions at the
	//   transport layer (TCP/SSL). See the following for additional details:
	//
	//     https://docs.aws.amazon.com/AmazonECS/latest/developerguide/load-balancer-types.html#nlb
	//
	// +unionDiscriminator
	// +required
	Type AWSLoadBalancerType `json:"type"`

	// classicLoadBalancerParameters holds configuration parameters for an AWS
	// classic load balancer. Present only if type is Classic.
	//
	// +optional
	ClassicLoadBalancerParameters *AWSClassicLoadBalancerParameters `json:"classicLoadBalancer,omitempty"`

	// networkLoadBalancerParameters holds configuration parameters for an AWS
	// network load balancer. Present only if type is NLB.
	//
	// +optional
	NetworkLoadBalancerParameters *AWSNetworkLoadBalancerParameters `json:"networkLoadBalancer,omitempty"`
}

// AWSLoadBalancerType is the type of AWS load balancer to instantiate.
// +kubebuilder:validation:Enum=Classic;NLB
type AWSLoadBalancerType string

const (
	AWSClassicLoadBalancer AWSLoadBalancerType = "Classic"
	AWSNetworkLoadBalancer AWSLoadBalancerType = "NLB"
)

// AWSSubnets contains a list of references to AWS subnets by
// ID or name.
// +kubebuilder:validation:XValidation:rule=`has(self.ids) && has(self.names) ? size(self.ids + self.names) <= 10 : true`,message="the total number of subnets cannot exceed 10"
// +kubebuilder:validation:XValidation:rule=`has(self.ids) && self.ids.size() > 0 || has(self.names) && self.names.size() > 0`,message="must specify at least 1 subnet name or id"
type AWSSubnets struct {
	// ids specifies a list of AWS subnets by subnet ID.
	// Subnet IDs must start with "subnet-", consist only
	// of alphanumeric characters, must be exactly 24
	// characters long, must be unique, and the total
	// number of subnets specified by ids and names
	// must not exceed 10.
	//
	// +optional
	// +listType=atomic
	// +kubebuilder:validation:XValidation:rule=`self.all(x, self.exists_one(y, x == y))`,message="subnet ids cannot contain duplicates"
	// + Note: Though it may seem redundant, MaxItems is necessary to prevent exceeding of the cost budget for the validation rules.
	// +kubebuilder:validation:MaxItems=10
	IDs []AWSSubnetID `json:"ids,omitempty"`

	// names specifies a list of AWS subnets by subnet name.
	// Subnet names must not start with "subnet-", must not
	// include commas, must be under 256 characters in length,
	// must be unique, and the total number of subnets
	// specified by ids and names must not exceed 10.
	//
	// +optional
	// +listType=atomic
	// +kubebuilder:validation:XValidation:rule=`self.all(x, self.exists_one(y, x == y))`,message="subnet names cannot contain duplicates"
	// + Note: Though it may seem redundant, MaxItems is necessary to prevent exceeding of the cost budget for the validation rules.
	// +kubebuilder:validation:MaxItems=10
	Names []AWSSubnetName `json:"names,omitempty"`
}

// AWSSubnetID is a reference to an AWS subnet ID.
// +kubebuilder:validation:MinLength=24
// +kubebuilder:validation:MaxLength=24
// +kubebuilder:validation:Pattern=`^subnet-[0-9A-Za-z]+$`
type AWSSubnetID string

// AWSSubnetName is a reference to an AWS subnet name.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=256
// +kubebuilder:validation:XValidation:rule=`!self.contains(',')`,message="subnet name cannot contain a comma"
// +kubebuilder:validation:XValidation:rule=`!self.startsWith('subnet-')`,message="subnet name cannot start with 'subnet-'"
type AWSSubnetName string

// GCPLoadBalancerParameters provides configuration settings that are
// specific to GCP load balancers.
type GCPLoadBalancerParameters struct {
	// clientAccess describes how client access is restricted for internal
	// load balancers.
	//
	// Valid values are:
	// * "Global": Specifying an internal load balancer with Global client access
	//   allows clients from any region within the VPC to communicate with the load
	//   balancer.
	//
	//     https://cloud.google.com/kubernetes-engine/docs/how-to/internal-load-balancing#global_access
	//
	// * "Local": Specifying an internal load balancer with Local client access
	//   means only clients within the same region (and VPC) as the GCP load balancer
	//   can communicate with the load balancer. Note that this is the default behavior.
	//
	//     https://cloud.google.com/load-balancing/docs/internal#client_access
	//
	// +optional
	ClientAccess GCPClientAccess `json:"clientAccess,omitempty"`
}

// GCPClientAccess describes how client access is restricted for internal
// load balancers.
// +kubebuilder:validation:Enum=Global;Local
type GCPClientAccess string

const (
	GCPGlobalAccess GCPClientAccess = "Global"
	GCPLocalAccess  GCPClientAccess = "Local"
)

// IBMLoadBalancerParameters provides configuration settings that are
// specific to IBM Cloud load balancers.
type IBMLoadBalancerParameters struct {
	// protocol specifies whether the load balancer uses PROXY protocol to forward connections to
	// the IngressController. See "service.kubernetes.io/ibm-load-balancer-cloud-provider-enable-features:
	// "proxy-protocol"" at https://cloud.ibm.com/docs/containers?topic=containers-vpc-lbaas"
	//
	// PROXY protocol can be used with load balancers that support it to
	// communicate the source addresses of client connections when
	// forwarding those connections to the IngressController.  Using PROXY
	// protocol enables the IngressController to report those source
	// addresses instead of reporting the load balancer's address in HTTP
	// headers and logs.  Note that enabling PROXY protocol on the
	// IngressController will cause connections to fail if you are not using
	// a load balancer that uses PROXY protocol to forward connections to
	// the IngressController.  See
	// http://www.haproxy.org/download/2.2/doc/proxy-protocol.txt for
	// information about PROXY protocol.
	//
	// Valid values for protocol are TCP, PROXY and omitted.
	// When omitted, this means no opinion and the platform is left to choose a reasonable default, which is subject to change over time.
	// The current default is TCP, without the proxy protocol enabled.
	//
	// +optional
	Protocol IngressControllerProtocol `json:"protocol,omitempty"`
}

// OpenStackLoadBalancerParameters provides configuration settings that are
// specific to OpenStack load balancers.
type OpenStackLoadBalancerParameters struct {
	// loadBalancerIP is tombstoned since the field was replaced by floatingIP.
	// LoadBalancerIP string `json:"loadBalancerIP,omitempty"`

	// floatingIP specifies the IP address that the load balancer will use.
	// When not specified, an IP address will be assigned randomly by the OpenStack cloud provider.
	// When specified, the floating IP has to be pre-created.  If the
	// specified value is not a floating IP or is already claimed, the
	// OpenStack cloud provider won't be able to provision the load
	// balancer.
	// This field may only be used if the IngressController has External scope.
	// This value must be a valid IPv4 or IPv6 address.
	// + ---
	// + Note: this field is meant to be set by the ingress controller
	// + to populate the `Service.Spec.LoadBalancerIP` field which has been
	// + deprecated in Kubernetes:
	// + https://github.com/kubernetes/kubernetes/pull/107235
	// + However, the field is still used by cloud-provider-openstack to reconcile
	// + the floating IP that we attach to the external load balancer.
	//
	// +kubebuilder:validation:XValidation:rule="isIP(self)",message="floatingIP must be a valid IPv4 or IPv6 address"
	// +optional
	FloatingIP string `json:"floatingIP,omitempty"`
}

// AWSClassicLoadBalancerParameters holds configuration parameters for an
// AWS Classic load balancer.
type AWSClassicLoadBalancerParameters struct {
	// connectionIdleTimeout specifies the maximum time period that a
	// connection may be idle before the load balancer closes the
	// connection.  The value must be parseable as a time duration value;
	// see <https://pkg.go.dev/time#ParseDuration>.  A nil or zero value
	// means no opinion, in which case a default value is used.  The default
	// value for this field is 60s.  This default is subject to change.
	//
	// +kubebuilder:validation:Format=duration
	// +optional
	ConnectionIdleTimeout metav1.Duration `json:"connectionIdleTimeout,omitempty"`

	// subnets specifies the subnets to which the load balancer will
	// attach. The subnets may be specified by either their
	// ID or name. The total number of subnets is limited to 10.
	//
	// In order for the load balancer to be provisioned with subnets,
	// each subnet must exist, each subnet must be from a different
	// availability zone, and the load balancer service must be
	// recreated to pick up new values.
	//
	// When omitted from the spec, the subnets will be auto-discovered
	// for each availability zone. Auto-discovered subnets are not reported
	// in the status of the IngressController object.
	//
	// +optional
	Subnets *AWSSubnets `json:"subnets,omitempty"`
}

// AWSNetworkLoadBalancerParameters holds configuration parameters for an
// AWS Network load balancer. For Example: Setting AWS EIPs https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html
// +kubebuilder:validation:XValidation:rule=`has(self.subnets) && has(self.subnets.ids) && has(self.subnets.names) && has(self.eipAllocations) ? size(self.subnets.ids + self.subnets.names) == size(self.eipAllocations) : true`,message="number of subnets must be equal to number of eipAllocations"
// +kubebuilder:validation:XValidation:rule=`has(self.subnets) && has(self.subnets.ids) && !has(self.subnets.names) && has(self.eipAllocations) ? size(self.subnets.ids) == size(self.eipAllocations) : true`,message="number of subnets must be equal to number of eipAllocations"
// +kubebuilder:validation:XValidation:rule=`has(self.subnets) && has(self.subnets.names) && !has(self.subnets.ids) && has(self.eipAllocations) ? size(self.subnets.names) == size(self.eipAllocations) : true`,message="number of subnets must be equal to number of eipAllocations"
type AWSNetworkLoadBalancerParameters struct {
	// subnets specifies the subnets to which the load balancer will
	// attach. The subnets may be specified by either their
	// ID or name. The total number of subnets is limited to 10.
	//
	// In order for the load balancer to be provisioned with subnets,
	// each subnet must exist, each subnet must be from a different
	// availability zone, and the load balancer service must be
	// recreated to pick up new values.
	//
	// When omitted from the spec, the subnets will be auto-discovered
	// for each availability zone. Auto-discovered subnets are not reported
	// in the status of the IngressController object.
	//
	// +optional
	Subnets *AWSSubnets `json:"subnets,omitempty"`

	// eipAllocations is a list of IDs for Elastic IP (EIP) addresses that
	// are assigned to the Network Load Balancer.
	// The following restrictions apply:
	//
	// eipAllocations can only be used with external scope, not internal.
	// An EIP can be allocated to only a single IngressController.
	// The number of EIP allocations must match the number of subnets that are used for the load balancer.
	// Each EIP allocation must be unique.
	// A maximum of 10 EIP allocations are permitted.
	//
	// See https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html for general
	// information about configuration, characteristics, and limitations of Elastic IP addresses.
	//
	// +optional
	// +listType=atomic
	// +kubebuilder:validation:XValidation:rule=`self.all(x, self.exists_one(y, x == y))`,message="eipAllocations cannot contain duplicates"
	// +kubebuilder:validation:MaxItems=10
	EIPAllocations []EIPAllocation `json:"eipAllocations"`

	// protocol specifies whether the Network Load Balancer uses PROXY
	// protocol to forward connections to the IngressController.
	//
	// When set to "TCP", the NLB uses AWS's native client IP preservation.
	// This may cause hairpin connection failures for internal load
	// balancers when connections are made from pods to router pods on
	// the same node.
	//
	// When set to "PROXY", the NLB disables native client IP preservation
	// and uses PROXY protocol v2. The IngressController enables PROXY
	// protocol on HAProxy so that it can parse PROXY protocol headers to
	// obtain the original client IP. This avoids hairpin connection
	// failures.
	//
	// The following values are valid for this field:
	//
	// * "TCP".
	// * "PROXY".
	//
	// When omitted, this means the user has no opinion and the value is
	// left to the platform to choose a reasonable default, which is subject to
	// change over time. The current default is "PROXY".
	//
	// Note that changing this field may cause brief connection failures
	// during the transition as the NLB attribute change and router rollout
	// occur independently.
	//
	// +optional
	Protocol NLBProtocol `json:"protocol,omitempty"`
}

// NLBProtocol specifies whether the AWS Network Load Balancer uses
// PROXY protocol to forward connections to the IngressController.
// +kubebuilder:validation:Enum=TCP;PROXY
// +enum
type NLBProtocol string

const (
	// NLBProtocolTCP instructs the NLB to forward connections using TCP
	// without PROXY protocol.
	NLBProtocolTCP NLBProtocol = "TCP"
	// NLBProtocolProxy instructs the NLB to forward connections using
	// PROXY protocol v2.
	NLBProtocolProxy NLBProtocol = "PROXY"
)

// EIPAllocation is an ID for an Elastic IP (EIP) address that can be allocated to an ELB in the AWS environment.
// Values must begin with `eipalloc-` followed by exactly 17 hexadecimal (`[0-9a-fA-F]`) characters.
// + Explanation of the regex `^eipalloc-[0-9a-fA-F]{17}$` for validating value of the EIPAllocation:
// + ^eipalloc- ensures the string starts with "eipalloc-".
// + [0-9a-fA-F]{17} matches exactly 17 hexadecimal characters (0-9, a-f, A-F).
// + $ ensures the string ends after the 17 hexadecimal characters.
// + Example of Valid and Invalid values:
// + eipalloc-1234567890abcdef1 is valid.
// + eipalloc-1234567890abcde is not valid (too short).
// + eipalloc-1234567890abcdefg is not valid (contains a non-hex character 'g').
// + Max length is calculated as follows:
// + eipalloc- = 9 chars and 17 hexadecimal chars after `-`
// + So, total is 17 + 9 = 26 chars required for value of an EIPAllocation.
//
// +kubebuilder:validation:MinLength=26
// +kubebuilder:validation:MaxLength=26
// +kubebuilder:validation:XValidation:rule=`self.startsWith('eipalloc-')`,message="eipAllocations should start with 'eipalloc-'"
// +kubebuilder:validation:XValidation:rule=`self.split("-", 2)[1].matches('[0-9a-fA-F]{17}$')`,message="eipAllocations must be 'eipalloc-' followed by exactly 17 hexadecimal characters (0-9, a-f, A-F)"
type EIPAllocation string

// HostNetworkStrategy holds parameters for the HostNetwork endpoint publishing
// strategy.
type HostNetworkStrategy struct {
	// protocol specifies whether the IngressController expects incoming
	// connections to use plain TCP or whether the IngressController expects
	// PROXY protocol.
	//
	// PROXY protocol can be used with load balancers that support it to
	// communicate the source addresses of client connections when
	// forwarding those connections to the IngressController.  Using PROXY
	// protocol enables the IngressController to report those source
	// addresses instead of reporting the load balancer's address in HTTP
	// headers and logs.  Note that enabling PROXY protocol on the
	// IngressController will cause connections to fail if you are not using
	// a load balancer that uses PROXY protocol to forward connections to
	// the IngressController.  See
	// http://www.haproxy.org/download/2.2/doc/proxy-protocol.txt for
	// information about PROXY protocol.
	//
	// The following values are valid for this field:
	//
	// * The empty string.
	// * "TCP".
	// * "PROXY".
	//
	// The empty string specifies the default, which is TCP without PROXY
	// protocol.  Note that the default is subject to change.
	//
	// +optional
	Protocol IngressControllerProtocol `json:"protocol,omitempty"`

	// httpPort is the port on the host which should be used to listen for
	// HTTP requests. This field should be set when port 80 is already in use.
	// The value should not coincide with the NodePort range of the cluster.
	// When the value is 0 or is not specified it defaults to 80.
	// +kubebuilder:validation:Maximum=65535
	// +kubebuilder:validation:Minimum=0
	// +kubebuilder:default=80
	// +optional
	HTTPPort int32 `json:"httpPort,omitempty"`

	// httpsPort is the port on the host which should be used to listen for
	// HTTPS requests. This field should be set when port 443 is already in use.
	// The value should not coincide with the NodePort range of the cluster.
	// When the value is 0 or is not specified it defaults to 443.
	// +kubebuilder:validation:Maximum=65535
	// +kubebuilder:validation:Minimum=0
	// +kubebuilder:default=443
	// +optional
	HTTPSPort int32 `json:"httpsPort,omitempty"`

	// statsPort is the port on the host where the stats from the router are
	// published. The value should not coincide with the NodePort range of the
	// cluster. If an external load balancer is configured to forward connections
	// to this IngressController, the load balancer should use this port for
	// health checks. The load balancer can send HTTP probes on this port on a
	// given node, with the path /healthz/ready to determine if the ingress
	// controller is ready to receive traffic on the node. For proper operation
	// the load balancer must not forward traffic to a node until the health
	// check reports ready. The load balancer should also stop forwarding requests
	// within a maximum of 45 seconds after /healthz/ready starts reporting
	// not-ready. Probing every 5 to 10 seconds, with a 5-second timeout and with
	// a threshold of two successful or failed requests to become healthy or
	// unhealthy respectively, are well-tested values. When the value is 0 or
	// is not specified it defaults to 1936.
	// +kubebuilder:validation:Maximum=65535
	// +kubebuilder:validation:Minimum=0
	// +kubebuilder:default=1936
	// +optional
	StatsPort int32 `json:"statsPort,omitempty"`
}

// PrivateStrategy holds parameters for the Private endpoint publishing
// strategy.
type PrivateStrategy struct {
	// protocol specifies whether the IngressController expects incoming
	// connections to use plain TCP or whether the IngressController expects
	// PROXY protocol.
	//
	// PROXY protocol can be used with load balancers that support it to
	// communicate the source addresses of client connections when
	// forwarding those connections to the IngressController.  Using PROXY
	// protocol enables the IngressController to report those source
	// addresses instead of reporting the load balancer's address in HTTP
	// headers and logs.  Note that enabling PROXY protocol on the
	// IngressController will cause connections to fail if you are not using
	// a load balancer that uses PROXY protocol to forward connections to
	// the IngressController.  See
	// http://www.haproxy.org/download/2.2/doc/proxy-protocol.txt for
	// information about PROXY protocol.
	//
	// The following values are valid for this field:
	//
	// * The empty string.
	// * "TCP".
	// * "PROXY".
	//
	// The empty string specifies the default, which is TCP without PROXY
	// protocol.  Note that the default is subject to change.
	//
	// +optional
	Protocol IngressControllerProtocol `json:"protocol,omitempty"`
}

// NodePortStrategy holds parameters for the NodePortService endpoint publishing strategy.
type NodePortStrategy struct {
	// protocol specifies whether the IngressController expects incoming
	// connections to use plain TCP or whether the IngressController expects
	// PROXY protocol.
	//
	// PROXY protocol can be used with load balancers that support it to
	// communicate the source addresses of client connections when
	// forwarding those connections to the IngressController.  Using PROXY
	// protocol enables the IngressController to report those source
	// addresses instead of reporting the load balancer's address in HTTP
	// headers and logs.  Note that enabling PROXY protocol on the
	// IngressController will cause connections to fail if you are not using
	// a load balancer that uses PROXY protocol to forward connections to
	// the IngressController.  See
	// http://www.haproxy.org/download/2.2/doc/proxy-protocol.txt for
	// information about PROXY protocol.
	//
	// The following values are valid for this field:
	//
	// * The empty string.
	// * "TCP".
	// * "PROXY".
	//
	// The empty string specifies the default, which is TCP without PROXY
	// protocol.  Note that the default is subject to change.
	//
	// +optional
	Protocol IngressControllerProtocol `json:"protocol,omitempty"`
}

// IngressControllerProtocol specifies whether PROXY protocol is enabled or not.
// +kubebuilder:validation:Enum="";TCP;PROXY
type IngressControllerProtocol string

const (
	DefaultProtocol IngressControllerProtocol = ""
	TCPProtocol     IngressControllerProtocol = "TCP"
	ProxyProtocol   IngressControllerProtocol = "PROXY"
)

// EndpointPublishingStrategy is a way to publish the endpoints of an
// IngressController, and represents the type and any additional configuration
// for a specific type.
// +union
type EndpointPublishingStrategy struct {
	// type is the publishing strategy to use. Valid values are:
	//
	// * LoadBalancerService
	//
	// Publishes the ingress controller using a Kubernetes LoadBalancer Service.
	//
	// In this configuration, the ingress controller deployment uses container
	// networking. A LoadBalancer Service is created to publish the deployment.
	//
	// See: https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer
	//
	// If domain is set, a wildcard DNS record will be managed to point at the
	// LoadBalancer Service's external name. DNS records are managed only in DNS
	// zones defined by dns.config.openshift.io/cluster .spec.publicZone and
	// .spec.privateZone.
	//
	// Wildcard DNS management is currently supported only on the AWS, Azure,
	// and GCP platforms.
	//
	// * HostNetwork
	//
	// Publishes the ingress controller on node ports where the ingress controller
	// is deployed.
	//
	// In this configuration, the ingress controller deployment uses host
	// networking, bound to node ports 80 and 443. The user is responsible for
	// configuring an external load balancer to publish the ingress controller via
	// the node ports.
	//
	// * Private
	//
	// Does not publish the ingress controller.
	//
	// In this configuration, the ingress controller deployment uses container
	// networking, and is not explicitly published. The user must manually publish
	// the ingress controller.
	//
	// * NodePortService
	//
	// Publishes the ingress controller using a Kubernetes NodePort Service.
	//
	// In this configuration, the ingress controller deployment uses container
	// networking. A NodePort Service is created to publish the deployment. The
	// specific node ports are dynamically allocated by OpenShift; however, to
	// support static port allocations, user changes to the node port
	// field of the managed NodePort Service will preserved.
	//
	// +unionDiscriminator
	// +required
	Type EndpointPublishingStrategyType `json:"type"`

	// loadBalancer holds parameters for the load balancer. Present only if
	// type is LoadBalancerService.
	// +optional
	LoadBalancer *LoadBalancerStrategy `json:"loadBalancer,omitempty"`

	// hostNetwork holds parameters for the HostNetwork endpoint publishing
	// strategy. Present only if type is HostNetwork.
	// +optional
	HostNetwork *HostNetworkStrategy `json:"hostNetwork,omitempty"`

	// private holds parameters for the Private endpoint publishing
	// strategy. Present only if type is Private.
	// +optional
	Private *PrivateStrategy `json:"private,omitempty"`

	// nodePort holds parameters for the NodePortService endpoint publishing strategy.
	// Present only if type is NodePortService.
	// +optional
	NodePort *NodePortStrategy `json:"nodePort,omitempty"`
}

// ClientCertificatePolicy describes the policy for client certificates.
// +kubebuilder:validation:Enum="";Required;Optional
type ClientCertificatePolicy string

const (
	// ClientCertificatePolicyRequired indicates that a client certificate
	// should be required.
	ClientCertificatePolicyRequired ClientCertificatePolicy = "Required"

	// ClientCertificatePolicyOptional indicates that a client certificate
	// should be requested but not required.
	ClientCertificatePolicyOptional ClientCertificatePolicy = "Optional"
)

// ClientTLS specifies TLS configuration to enable client-to-server
// authentication, which can be used for mutual TLS.
type ClientTLS struct {
	// clientCertificatePolicy specifies whether the ingress controller
	// requires clients to provide certificates.  This field accepts the
	// values "Required" or "Optional".
	//
	// Note that the ingress controller only checks client certificates for
	// edge-terminated and reencrypt TLS routes; it cannot check
	// certificates for cleartext HTTP or passthrough TLS routes.
	//
	// +required
	ClientCertificatePolicy ClientCertificatePolicy `json:"clientCertificatePolicy"`

	// clientCA specifies a configmap containing the PEM-encoded CA
	// certificate bundle that should be used to verify a client's
	// certificate.  The administrator must create this configmap in the
	// openshift-config namespace.
	//
	// +required
	ClientCA configv1.ConfigMapNameReference `json:"clientCA"`

	// allowedSubjectPatterns specifies a list of regular expressions that
	// should be matched against the distinguished name on a valid client
	// certificate to filter requests.  The regular expressions must use
	// PCRE syntax.  If this list is empty, no filtering is performed.  If
	// the list is nonempty, then at least one pattern must match a client
	// certificate's distinguished name or else the ingress controller
	// rejects the certificate and denies the connection.
	//
	// +listType=atomic
	// +optional
	AllowedSubjectPatterns []string `json:"allowedSubjectPatterns,omitempty"`
}

// RouteAdmissionPolicy is an admission policy for allowing new route claims.
type RouteAdmissionPolicy struct {
	// namespaceOwnership describes how host name claims across namespaces should
	// be handled.
	//
	// Value must be one of:
	//
	// - Strict: Do not allow routes in different namespaces to claim the same host.
	//
	// - InterNamespaceAllowed: Allow routes to claim different paths of the same
	//   host name across namespaces.
	//
	// If empty, the default is Strict.
	// +optional
	NamespaceOwnership NamespaceOwnershipCheck `json:"namespaceOwnership,omitempty"`
	// wildcardPolicy describes how routes with wildcard policies should
	// be handled for the ingress controller. WildcardPolicy controls use
	// of routes [1] exposed by the ingress controller based on the route's
	// wildcard policy.
	//
	// [1] https://github.com/openshift/api/blob/master/route/v1/types.go
	//
	// Note: Updating WildcardPolicy from WildcardsAllowed to WildcardsDisallowed
	// will cause admitted routes with a wildcard policy of Subdomain to stop
	// working. These routes must be updated to a wildcard policy of None to be
	// readmitted by the ingress controller.
	//
	// WildcardPolicy supports WildcardsAllowed and WildcardsDisallowed values.
	//
	// If empty, defaults to "WildcardsDisallowed".
	//
	WildcardPolicy WildcardPolicy `json:"wildcardPolicy,omitempty"`
}

// WildcardPolicy is a route admission policy component that describes how
// routes with a wildcard policy should be handled.
// +kubebuilder:validation:Enum=WildcardsAllowed;WildcardsDisallowed
type WildcardPolicy string

const (
	// WildcardPolicyAllowed indicates routes with any wildcard policy are
	// admitted by the ingress controller.
	WildcardPolicyAllowed WildcardPolicy = "WildcardsAllowed"

	// WildcardPolicyDisallowed indicates only routes with a wildcard policy
	// of None are admitted by the ingress controller.
	WildcardPolicyDisallowed WildcardPolicy = "WildcardsDisallowed"
)

// NamespaceOwnershipCheck is a route admission policy component that describes
// how host name claims across namespaces should be handled.
// +kubebuilder:validation:Enum=InterNamespaceAllowed;Strict
type NamespaceOwnershipCheck string

const (
	// InterNamespaceAllowedOwnershipCheck allows routes to claim different paths of the same host name across namespaces.
	InterNamespaceAllowedOwnershipCheck NamespaceOwnershipCheck = "InterNamespaceAllowed"

	// StrictNamespaceOwnershipCheck does not allow routes to claim the same host name across namespaces.
	StrictNamespaceOwnershipCheck NamespaceOwnershipCheck = "Strict"
)

// LoggingDestinationType is a type of destination to which to send log
// messages.
//
// +kubebuilder:validation:Enum=Container;Syslog
type LoggingDestinationType string

const (
	// Container sends log messages to a sidecar container.
	ContainerLoggingDestinationType LoggingDestinationType = "Container"

	// Syslog sends log messages to a syslog endpoint.
	SyslogLoggingDestinationType LoggingDestinationType = "Syslog"

	// ContainerLoggingSidecarContainerName is the name of the container
	// with the log output in an ingress controller pod when container
	// logging is used.
	ContainerLoggingSidecarContainerName = "logs"
)

// SyslogLoggingDestinationParameters describes parameters for the Syslog
// logging destination type.
type SyslogLoggingDestinationParameters struct {
	// address is the IP address of the syslog endpoint that receives log
	// messages.
	//
	// +required
	Address string `json:"address"`

	// port is the UDP port number of the syslog endpoint that receives log
	// messages.
	//
	// +kubebuilder:validation:Minimum=1
	// +kubebuilder:validation:Maximum=65535
	// +required
	Port uint32 `json:"port"`

	// facility specifies the syslog facility of log messages.
	//
	// If this field is empty, the facility is "local1".
	//
	// +kubebuilder:validation:Enum=kern;user;mail;daemon;auth;syslog;lpr;news;uucp;cron;auth2;ftp;ntp;audit;alert;cron2;local0;local1;local2;local3;local4;local5;local6;local7
	// +optional
	Facility string `json:"facility,omitempty"`

	// maxLength is the maximum length of the log message.
	//
	// Valid values are integers in the range 480 to 4096, inclusive.
	//
	// When omitted, the default value is 1024.
	//
	// +kubebuilder:validation:Maximum=4096
	// +kubebuilder:validation:Minimum=480
	// +kubebuilder:default=1024
	// +default:=1024
	// +optional
	MaxLength uint32 `json:"maxLength,omitempty"`
}

// ContainerLoggingDestinationParameters describes parameters for the Container
// logging destination type.
type ContainerLoggingDestinationParameters struct {
	// maxLength is the maximum length of the log message.
	//
	// Valid values are integers in the range 480 to 8192, inclusive.
	//
	// When omitted, the default value is 1024.
	//
	// +kubebuilder:validation:Maximum=8192
	// +kubebuilder:validation:Minimum=480
	// +kubebuilder:default=1024
	// +default:=1024
	// +optional
	MaxLength int32 `json:"maxLength,omitempty"`
}

// LoggingDestination describes a destination for log messages.
// +union
type LoggingDestination struct {
	// type is the type of destination for logs.  It must be one of the
	// following:
	//
	// * Container
	//
	// The ingress operator configures the sidecar container named "logs" on
	// the ingress controller pod and configures the ingress controller to
	// write logs to the sidecar.  The logs are then available as container
	// logs.  The expectation is that the administrator configures a custom
	// logging solution that reads logs from this sidecar.  Note that using
	// container logs means that logs may be dropped if the rate of logs
	// exceeds the container runtime's or the custom logging solution's
	// capacity.
	//
	// * Syslog
	//
	// Logs are sent to a syslog endpoint.  The administrator must specify
	// an endpoint that can receive syslog messages.  The expectation is
	// that the administrator has configured a custom syslog instance.
	//
	// +unionDiscriminator
	// +required
	Type LoggingDestinationType `json:"type"`

	// syslog holds parameters for a syslog endpoint.  Present only if
	// type is Syslog.
	//
	// +optional
	Syslog *SyslogLoggingDestinationParameters `json:"syslog,omitempty"`

	// container holds parameters for the Container logging destination.
	// Present only if type is Container.
	//
	// +optional
	Container *ContainerLoggingDestinationParameters `json:"container,omitempty"`
}

// IngressControllerCaptureHTTPHeader describes an HTTP header that should be
// captured.
type IngressControllerCaptureHTTPHeader struct {
	// name specifies a header name.  Its value must be a valid HTTP header
	// name as defined in RFC 2616 section 4.2.
	//
	// +kubebuilder:validation:Pattern="^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$"
	// +required
	Name string `json:"name"`

	// maxLength specifies a maximum length for the header value.  If a
	// header value exceeds this length, the value will be truncated in the
	// log message.  Note that the ingress controller may impose a separate
	// bound on the total length of HTTP headers in a request.
	//
	// +kubebuilder:validation:Minimum=1
	// +required
	MaxLength int `json:"maxLength"`
}

// IngressControllerCaptureHTTPHeaders specifies which HTTP headers the
// IngressController captures.
type IngressControllerCaptureHTTPHeaders struct {
	// request specifies which HTTP request headers to capture.
	//
	// If this field is empty, no request headers are captured.
	//
	// +nullable
	// +optional
	// +listType=atomic
	Request []IngressControllerCaptureHTTPHeader `json:"request,omitempty"`

	// response specifies which HTTP response headers to capture.
	//
	// If this field is empty, no response headers are captured.
	//
	// +nullable
	// +optional
	// +listType=atomic
	Response []IngressControllerCaptureHTTPHeader `json:"response,omitempty"`
}

// CookieMatchType indicates the type of matching used against cookie names to
// select a cookie for capture.
// +kubebuilder:validation:Enum=Exact;Prefix
type CookieMatchType string

const (
	// CookieMatchTypeExact indicates that an exact string match should be
	// performed.
	CookieMatchTypeExact CookieMatchType = "Exact"
	// CookieMatchTypePrefix indicates that a string prefix match should be
	// performed.
	CookieMatchTypePrefix CookieMatchType = "Prefix"
)

// IngressControllerCaptureHTTPCookie describes an HTTP cookie that should be
// captured.
type IngressControllerCaptureHTTPCookie struct {
	IngressControllerCaptureHTTPCookieUnion `json:",inline"`

	// maxLength specifies a maximum length of the string that will be
	// logged, which includes the cookie name, cookie value, and
	// one-character delimiter.  If the log entry exceeds this length, the
	// value will be truncated in the log message.  Note that the ingress
	// controller may impose a separate bound on the total length of HTTP
	// headers in a request.
	//
	// +kubebuilder:validation:Minimum=1
	// +kubebuilder:validation:Maximum=1024
	// +required
	MaxLength int `json:"maxLength"`
}

// IngressControllerCaptureHTTPCookieUnion describes optional fields of an HTTP cookie that should be captured.
// +union
type IngressControllerCaptureHTTPCookieUnion struct {
	// matchType specifies the type of match to be performed on the cookie
	// name.  Allowed values are "Exact" for an exact string match and
	// "Prefix" for a string prefix match.  If "Exact" is specified, a name
	// must be specified in the name field.  If "Prefix" is provided, a
	// prefix must be specified in the namePrefix field.  For example,
	// specifying matchType "Prefix" and namePrefix "foo" will capture a
	// cookie named "foo" or "foobar" but not one named "bar".  The first
	// matching cookie is captured.
	//
	// +unionDiscriminator
	// +required
	MatchType CookieMatchType `json:"matchType"`

	// name specifies a cookie name.  Its value must be a valid HTTP cookie
	// name as defined in RFC 6265 section 4.1.
	//
	// +kubebuilder:validation:Pattern="^[-!#$%&'*+.0-9A-Z^_`a-z|~]*$"
	// +kubebuilder:validation:MinLength=0
	// +kubebuilder:validation:MaxLength=1024
	// +optional
	Name string `json:"name"`

	// namePrefix specifies a cookie name prefix.  Its value must be a valid
	// HTTP cookie name as defined in RFC 6265 section 4.1.
	//
	// +kubebuilder:validation:Pattern="^[-!#$%&'*+.0-9A-Z^_`a-z|~]*$"
	// +kubebuilder:validation:MinLength=0
	// +kubebuilder:validation:MaxLength=1024
	// +optional
	NamePrefix string `json:"namePrefix"`
}

// LoggingPolicy indicates how an event should be logged.
// +kubebuilder:validation:Enum=Log;Ignore
type LoggingPolicy string

const (
	// LoggingPolicyLog indicates that an event should be logged.
	LoggingPolicyLog LoggingPolicy = "Log"
	// LoggingPolicyIgnore indicates that an event should not be logged.
	LoggingPolicyIgnore LoggingPolicy = "Ignore"
)

// AccessLogging describes how client requests should be logged.
type AccessLogging struct {
	// destination is where access logs go.
	//
	// +required
	Destination LoggingDestination `json:"destination"`

	// httpLogFormat specifies the format of the log message for an HTTP
	// request.
	//
	// If this field is empty, log messages use the implementation's default
	// HTTP log format.  For HAProxy's default HTTP log format, see the
	// HAProxy documentation:
	// http://cbonte.github.io/haproxy-dconv/2.0/configuration.html#8.2.3
	//
	// Note that this format only applies to cleartext HTTP connections
	// and to secure HTTP connections for which the ingress controller
	// terminates encryption (that is, edge-terminated or reencrypt
	// connections).  It does not affect the log format for TLS passthrough
	// connections.
	//
	// +optional
	HttpLogFormat string `json:"httpLogFormat,omitempty"`

	// httpCaptureHeaders defines HTTP headers that should be captured in
	// access logs.  If this field is empty, no headers are captured.
	//
	// Note that this option only applies to cleartext HTTP connections
	// and to secure HTTP connections for which the ingress controller
	// terminates encryption (that is, edge-terminated or reencrypt
	// connections).  Headers cannot be captured for TLS passthrough
	// connections.
	//
	// +optional
	HTTPCaptureHeaders IngressControllerCaptureHTTPHeaders `json:"httpCaptureHeaders,omitempty"`

	// httpCaptureCookies specifies HTTP cookies that should be captured in
	// access logs.  If this field is empty, no cookies are captured.
	//
	// +nullable
	// +optional
	// +kubebuilder:validation:MaxItems=1
	// +listType=atomic
	HTTPCaptureCookies []IngressControllerCaptureHTTPCookie `json:"httpCaptureCookies,omitempty"`

	// logEmptyRequests specifies how connections on which no request is
	// received should be logged.  Typically, these empty requests come from
	// load balancers' health probes or Web browsers' speculative
	// connections ("preconnect"), in which case logging these requests may
	// be undesirable.  However, these requests may also be caused by
	// network errors, in which case logging empty requests may be useful
	// for diagnosing the errors.  In addition, these requests may be caused
	// by port scans, in which case logging empty requests may aid in
	// detecting intrusion attempts.  Allowed values for this field are
	// "Log" and "Ignore".  The default value is "Log".
	//
	// +optional
	// +kubebuilder:default:="Log"
	LogEmptyRequests LoggingPolicy `json:"logEmptyRequests,omitempty"`
}

// IngressControllerLogging describes what should be logged where.
type IngressControllerLogging struct {
	// access describes how the client requests should be logged.
	//
	// If this field is empty, access logging is disabled.
	//
	// +optional
	Access *AccessLogging `json:"access,omitempty"`
}

// IngressControllerHTTPHeaderPolicy is a policy for setting HTTP headers.
//
// +kubebuilder:validation:Enum=Append;Replace;IfNone;Never
type IngressControllerHTTPHeaderPolicy string

const (
	// AppendHTTPHeaderPolicy appends the header, preserving any existing header.
	AppendHTTPHeaderPolicy IngressControllerHTTPHeaderPolicy = "Append"
	// ReplaceHTTPHeaderPolicy sets the header, removing any existing header.
	ReplaceHTTPHeaderPolicy IngressControllerHTTPHeaderPolicy = "Replace"
	// IfNoneHTTPHeaderPolicy sets the header if it is not already set.
	IfNoneHTTPHeaderPolicy IngressControllerHTTPHeaderPolicy = "IfNone"
	// NeverHTTPHeaderPolicy never sets the header, preserving any existing
	// header.
	NeverHTTPHeaderPolicy IngressControllerHTTPHeaderPolicy = "Never"
)

// IngressControllerHTTPUniqueIdHeaderPolicy describes configuration for a
// unique id header.
type IngressControllerHTTPUniqueIdHeaderPolicy struct {
	// name specifies the name of the HTTP header (for example, "unique-id")
	// that the ingress controller should inject into HTTP requests.  The
	// field's value must be a valid HTTP header name as defined in RFC 2616
	// section 4.2.  If the field is empty, no header is injected.
	//
	// +optional
	// +kubebuilder:validation:Pattern="^$|^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$"
	// +kubebuilder:validation:MinLength=0
	// +kubebuilder:validation:MaxLength=1024
	Name string `json:"name,omitempty"`

	// format specifies the format for the injected HTTP header's value.
	// This field has no effect unless name is specified.  For the
	// HAProxy-based ingress controller implementation, this format uses the
	// same syntax as the HTTP log format.  If the field is empty, the
	// default value is "%{+X}o\\ %ci:%cp_%fi:%fp_%Ts_%rt:%pid"; see the
	// corresponding HAProxy documentation:
	// http://cbonte.github.io/haproxy-dconv/2.0/configuration.html#8.2.3
	//
	// +optional
	// +kubebuilder:validation:Pattern="^(%(%|(\\{[-+]?[QXE](,[-+]?[QXE])*\\})?([A-Za-z]+|\\[[.0-9A-Z_a-z]+(\\([^)]+\\))?(,[.0-9A-Z_a-z]+(\\([^)]+\\))?)*\\]))|[^%[:cntrl:]])*$"
	// +kubebuilder:validation:MinLength=0
	// +kubebuilder:validation:MaxLength=1024
	Format string `json:"format,omitempty"`
}

// IngressControllerHTTPHeaderNameCaseAdjustment is the name of an HTTP header
// (for example, "X-Forwarded-For") in the desired capitalization.  The value
// must be a valid HTTP header name as defined in RFC 2616 section 4.2.
//
// +kubebuilder:validation:Pattern="^$|^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$"
// +kubebuilder:validation:MinLength=0
// +kubebuilder:validation:MaxLength=1024
type IngressControllerHTTPHeaderNameCaseAdjustment string

// IngressControllerHTTPHeaders specifies how the IngressController handles
// certain HTTP headers.
type IngressControllerHTTPHeaders struct {
	// forwardedHeaderPolicy specifies when and how the IngressController
	// sets the Forwarded, X-Forwarded-For, X-Forwarded-Host,
	// X-Forwarded-Port, X-Forwarded-Proto, and X-Forwarded-Proto-Version
	// HTTP headers.  The value may be one of the following:
	//
	// * "Append", which specifies that the IngressController appends the
	//   headers, preserving existing headers.
	//
	// * "Replace", which specifies that the IngressController sets the
	//   headers, replacing any existing Forwarded or X-Forwarded-* headers.
	//
	// * "IfNone", which specifies that the IngressController sets the
	//   headers if they are not already set.
	//
	// * "Never", which specifies that the IngressController never sets the
	//   headers, preserving any existing headers.
	//
	// By default, the policy is "Append".
	//
	// +optional
	ForwardedHeaderPolicy IngressControllerHTTPHeaderPolicy `json:"forwardedHeaderPolicy,omitempty"`

	// uniqueId describes configuration for a custom HTTP header that the
	// ingress controller should inject into incoming HTTP requests.
	// Typically, this header is configured to have a value that is unique
	// to the HTTP request.  The header can be used by applications or
	// included in access logs to facilitate tracing individual HTTP
	// requests.
	//
	// If this field is empty, no such header is injected into requests.
	//
	// +optional
	UniqueId IngressControllerHTTPUniqueIdHeaderPolicy `json:"uniqueId,omitempty"`

	// headerNameCaseAdjustments specifies case adjustments that can be
	// applied to HTTP header names.  Each adjustment is specified as an
	// HTTP header name with the desired capitalization.  For example,
	// specifying "X-Forwarded-For" indicates that the "x-forwarded-for"
	// HTTP header should be adjusted to have the specified capitalization.
	//
	// These adjustments are only applied to cleartext, edge-terminated, and
	// re-encrypt routes, and only when using HTTP/1.
	//
	// For request headers, these adjustments are applied only for routes
	// that have the haproxy.router.openshift.io/h1-adjust-case=true
	// annotation.  For response headers, these adjustments are applied to
	// all HTTP responses.
	//
	// If this field is empty, no request headers are adjusted.
	//
	// +nullable
	// +optional
	// +listType=atomic
	HeaderNameCaseAdjustments []IngressControllerHTTPHeaderNameCaseAdjustment `json:"headerNameCaseAdjustments,omitempty"`

	// actions specifies options for modifying headers and their values.
	// Note that this option only applies to cleartext HTTP connections
	// and to secure HTTP connections for which the ingress controller
	// terminates encryption (that is, edge-terminated or reencrypt
	// connections).  Headers cannot be modified for TLS passthrough
	// connections.
	// Setting the HSTS (`Strict-Transport-Security`) header is not supported via actions. `Strict-Transport-Security`
	// may only be configured using the "haproxy.router.openshift.io/hsts_header" route annotation, and only in
	// accordance with the policy specified in Ingress.Spec.RequiredHSTSPolicies.
	// Any actions defined here are applied after any actions related to the following other fields:
	// cache-control, spec.clientTLS,
	// spec.httpHeaders.forwardedHeaderPolicy, spec.httpHeaders.uniqueId,
	// and spec.httpHeaders.headerNameCaseAdjustments.
	// In case of HTTP request headers, the actions specified in spec.httpHeaders.actions on the Route will be executed after
	// the actions specified in the IngressController's spec.httpHeaders.actions field.
	// In case of HTTP response headers, the actions specified in spec.httpHeaders.actions on the IngressController will be
	// executed after the actions specified in the Route's spec.httpHeaders.actions field.
	// Headers set using this API cannot be captured for use in access logs.
	// The following header names are reserved and may not be modified via this API:
	// Strict-Transport-Security, Proxy, Host, Cookie, Set-Cookie.
	// Note that the total size of all net added headers *after* interpolating dynamic values
	// must not exceed the value of spec.tuningOptions.headerBufferMaxRewriteBytes on the
	// IngressController. Please refer to the documentation
	// for that API field for more details.
	// +optional
	Actions IngressControllerHTTPHeaderActions `json:"actions,omitempty"`
}

// IngressControllerHTTPHeaderActions defines configuration for actions on HTTP request and response headers.
type IngressControllerHTTPHeaderActions struct {
	// response is a list of HTTP response headers to modify.
	// Actions defined here will modify the response headers of all requests passing through an ingress controller.
	// These actions are applied to all Routes i.e. for all connections handled by the ingress controller defined within a cluster.
	// IngressController actions for response headers will be executed after Route actions.
	// Currently, actions may define to either `Set` or `Delete` headers values.
	// Actions are applied in sequence as defined in this list.
	// A maximum of 20 response header actions may be configured.
	// Sample fetchers allowed are "res.hdr" and "ssl_c_der".
	// Converters allowed are "lower" and "base64".
	// Example header values: "%[res.hdr(X-target),lower]", "%{+Q}[ssl_c_der,base64]".
	// +listType=map
	// +listMapKey=name
	// +optional
	// +kubebuilder:validation:MaxItems=20
	// +kubebuilder:validation:XValidation:rule=`self.all(key, key.action.type == "Delete" || (has(key.action.set) && key.action.set.value.matches('^(?:%(?:%|(?:\\{[-+]?[QXE](?:,[-+]?[QXE])*\\})?\\[(?:res\\.hdr\\([0-9A-Za-z-]+\\)|ssl_c_der)(?:,(?:lower|base64))*\\])|[^%[:cntrl:]])+$')))`,message="Either the header value provided is not in correct format or the sample fetcher/converter specified is not allowed. The dynamic header value will be interpreted as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 and may use HAProxy's %[] syntax and otherwise must be a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. Sample fetchers allowed are res.hdr, ssl_c_der. Converters allowed are lower, base64."
	Response []IngressControllerHTTPHeader `json:"response"`
	// request is a list of HTTP request headers to modify.
	// Actions defined here will modify the request headers of all requests passing through an ingress controller.
	// These actions are applied to all Routes i.e. for all connections handled by the ingress controller defined within a cluster.
	// IngressController actions for request headers will be executed before Route actions.
	// Currently, actions may define to either `Set` or `Delete` headers values.
	// Actions are applied in sequence as defined in this list.
	// A maximum of 20 request header actions may be configured.
	// Sample fetchers allowed are "req.hdr" and "ssl_c_der".
	// Converters allowed are "lower" and "base64".
	// Example header values: "%[req.hdr(X-target),lower]", "%{+Q}[ssl_c_der,base64]".
	// + ---
	// + Note: Any change to regex mentioned below must be reflected in the CRD validation of route in https://github.com/openshift/library-go/blob/master/pkg/route/validation/validation.go and vice-versa.
	// +listType=map
	// +listMapKey=name
	// +optional
	// +kubebuilder:validation:MaxItems=20
	// +kubebuilder:validation:XValidation:rule=`self.all(key, key.action.type == "Delete" || (has(key.action.set) && key.action.set.value.matches('^(?:%(?:%|(?:\\{[-+]?[QXE](?:,[-+]?[QXE])*\\})?\\[(?:req\\.hdr\\([0-9A-Za-z-]+\\)|ssl_c_der)(?:,(?:lower|base64))*\\])|[^%[:cntrl:]])+$')))`,message="Either the header value provided is not in correct format or the sample fetcher/converter specified is not allowed. The dynamic header value will be interpreted as an HAProxy format string as defined in http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6 and may use HAProxy's %[] syntax and otherwise must be a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2. Sample fetchers allowed are req.hdr, ssl_c_der. Converters allowed are lower, base64."
	Request []IngressControllerHTTPHeader `json:"request"`
}

// IngressControllerHTTPHeader specifies configuration for setting or deleting an HTTP header.
type IngressControllerHTTPHeader struct {
	// name specifies the name of a header on which to perform an action. Its value must be a valid HTTP header
	// name as defined in RFC 2616 section 4.2.
	// The name must consist only of alphanumeric and the following special characters, "-!#$%&'*+.^_`".
	// The following header names are reserved and may not be modified via this API:
	// Strict-Transport-Security, Proxy, Host, Cookie, Set-Cookie.
	// It must be no more than 255 characters in length.
	// Header name must be unique.
	// +required
	// +kubebuilder:validation:MinLength=1
	// +kubebuilder:validation:MaxLength=255
	// +kubebuilder:validation:Pattern="^[-!#$%&'*+.0-9A-Z^_`a-z|~]+$"
	// +kubebuilder:validation:XValidation:rule="self.lowerAscii() != 'strict-transport-security'",message="strict-transport-security header may not be modified via header actions"
	// +kubebuilder:validation:XValidation:rule="self.lowerAscii() != 'proxy'",message="proxy header may not be modified via header actions"
	// +kubebuilder:validation:XValidation:rule="self.lowerAscii() != 'host'",message="host header may not be modified via header actions"
	// +kubebuilder:validation:XValidation:rule="self.lowerAscii() != 'cookie'",message="cookie header may not be modified via header actions"
	// +kubebuilder:validation:XValidation:rule="self.lowerAscii() != 'set-cookie'",message="set-cookie header may not be modified via header actions"
	Name string `json:"name"`
	// action specifies actions to perform on headers, such as setting or deleting headers.
	// +required
	Action IngressControllerHTTPHeaderActionUnion `json:"action"`
}

// IngressControllerHTTPHeaderActionUnion specifies an action to take on an HTTP header.
// +kubebuilder:validation:XValidation:rule="has(self.type) && self.type == 'Set' ?  has(self.set) : !has(self.set)",message="set is required when type is Set, and forbidden otherwise"
// +union
type IngressControllerHTTPHeaderActionUnion struct {
	// type defines the type of the action to be applied on the header.
	// Possible values are Set or Delete.
	// Set allows you to set HTTP request and response headers.
	// Delete allows you to delete HTTP request and response headers.
	// +unionDiscriminator
	// +kubebuilder:validation:Enum:=Set;Delete
	// +required
	Type IngressControllerHTTPHeaderActionType `json:"type"`

	// set specifies how the HTTP header should be set.
	// This field is required when type is Set and forbidden otherwise.
	// +optional
	// +unionMember
	Set *IngressControllerSetHTTPHeader `json:"set,omitempty"`
}

// IngressControllerHTTPHeaderActionType defines actions that can be performed on HTTP headers.
type IngressControllerHTTPHeaderActionType string

const (
	// Set specifies that an HTTP header should be set.
	Set IngressControllerHTTPHeaderActionType = "Set"
	// Delete specifies that an HTTP header should be deleted.
	Delete IngressControllerHTTPHeaderActionType = "Delete"
)

// IngressControllerSetHTTPHeader defines the value which needs to be set on an HTTP header.
type IngressControllerSetHTTPHeader struct {
	// value specifies a header value.
	// Dynamic values can be added. The value will be interpreted as an HAProxy format string as defined in
	// http://cbonte.github.io/haproxy-dconv/2.6/configuration.html#8.2.6  and may use HAProxy's %[] syntax and
	// otherwise must be a valid HTTP header value as defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.
	// The value of this field must be no more than 16384 characters in length.
	// Note that the total size of all net added headers *after* interpolating dynamic values
	// must not exceed the value of spec.tuningOptions.headerBufferMaxRewriteBytes on the
	// IngressController.
	// + ---
	// + Note: This limit was selected as most common web servers have a limit of 16384 characters or some lower limit.
	// + See <https://www.geekersdigest.com/max-http-request-header-size-server-comparison/>.
	// +required
	// +kubebuilder:validation:MinLength=1
	// +kubebuilder:validation:MaxLength=16384
	Value string `json:"value"`
}

// IngressControllerTuningOptions specifies options for tuning the performance
// of ingress controller pods
type IngressControllerTuningOptions struct {
	// headerBufferBytes describes how much memory should be reserved
	// (in bytes) for IngressController connection sessions.
	// Note that this value must be at least 16384 if HTTP/2 is
	// enabled for the IngressController (https://tools.ietf.org/html/rfc7540).
	// If this field is empty, the IngressController will use a default value
	// of 32768 bytes.
	//
	// Setting this field is generally not recommended as headerBufferBytes
	// values that are too small may break the IngressController and
	// headerBufferBytes values that are too large could cause the
	// IngressController to use significantly more memory than necessary.
	//
	// +kubebuilder:validation:Minimum=16384
	// +optional
	HeaderBufferBytes int32 `json:"headerBufferBytes,omitempty"`

	// headerBufferMaxRewriteBytes describes how much memory should be reserved
	// (in bytes) from headerBufferBytes for HTTP header rewriting
	// and appending for IngressController connection sessions.
	// Note that incoming HTTP requests will be limited to
	// (headerBufferBytes - headerBufferMaxRewriteBytes) bytes, meaning
	// headerBufferBytes must be greater than headerBufferMaxRewriteBytes.
	// If this field is empty, the IngressController will use a default value
	// of 8192 bytes.
	//
	// Setting this field is generally not recommended as
	// headerBufferMaxRewriteBytes values that are too small may break the
	// IngressController and headerBufferMaxRewriteBytes values that are too
	// large could cause the IngressController to use significantly more memory
	// than necessary.
	//
	// +kubebuilder:validation:Minimum=4096
	// +optional
	HeaderBufferMaxRewriteBytes int32 `json:"headerBufferMaxRewriteBytes,omitempty"`

	// threadCount defines the number of threads created per HAProxy process.
	// Creating more threads allows each ingress controller pod to handle more
	// connections, at the cost of more system resources being used. HAProxy
	// currently supports up to 64 threads. If this field is empty, the
	// IngressController will use the default value.  The current default is 4
	// threads, but this may change in future releases.
	//
	// Setting this field is generally not recommended. Increasing the number
	// of HAProxy threads allows ingress controller pods to utilize more CPU
	// time under load, potentially starving other pods if set too high.
	// Reducing the number of threads may cause the ingress controller to
	// perform poorly.
	//
	// +kubebuilder:validation:Minimum=1
	// +kubebuilder:validation:Maximum=64
	// +optional
	ThreadCount int32 `json:"threadCount,omitempty"`

	// clientTimeout defines how long a connection will be held open while
	// waiting for a client response.
	//
	// If unset, the default timeout is 30s
	// +kubebuilder:validation:Format=duration
	// +optional
	ClientTimeout *metav1.Duration `json:"clientTimeout,omitempty"`

	// clientFinTimeout defines how long a connection will be held open while
	// waiting for the client response to the server/backend closing the
	// connection.
	//
	// If unset, the default timeout is 1s
	// +kubebuilder:validation:Format=duration
	// +optional
	ClientFinTimeout *metav1.Duration `json:"clientFinTimeout,omitempty"`

	// serverTimeout defines how long a connection will be held open while
	// waiting for a server/backend response.
	//
	// If unset, the default timeout is 30s
	// +kubebuilder:validation:Format=duration
	// +optional
	ServerTimeout *metav1.Duration `json:"serverTimeout,omitempty"`

	// serverFinTimeout defines how long a connection will be held open while
	// waiting for the server/backend response to the client closing the
	// connection.
	//
	// If unset, the default timeout is 1s
	// +kubebuilder:validation:Format=duration
	// +optional
	ServerFinTimeout *metav1.Duration `json:"serverFinTimeout,omitempty"`

	// tunnelTimeout defines how long a tunnel connection (including
	// websockets) will be held open while the tunnel is idle.
	//
	// If unset, the default timeout is 1h
	// +kubebuilder:validation:Format=duration
	// +optional
	TunnelTimeout *metav1.Duration `json:"tunnelTimeout,omitempty"`

	// connectTimeout defines the maximum time to wait for
	// a connection attempt to a server/backend to succeed.
	//
	// This field expects an unsigned duration string of decimal numbers, each with optional
	// fraction and a unit suffix, e.g. "300ms", "1.5h" or "2h45m".
	// Valid time units are "ns", "us" (or "µs" U+00B5 or "μs" U+03BC), "ms", "s", "m", "h".
	//
	// When omitted, this means the user has no opinion and the platform is left
	// to choose a reasonable default. This default is subject to change over time.
	// The current default is 5s.
	//
	// +kubebuilder:validation:Pattern=^(0|([0-9]+(\.[0-9]+)?(ns|us|µs|μs|ms|s|m|h))+)$
	// +kubebuilder:validation:Type:=string
	// +optional
	ConnectTimeout *metav1.Duration `json:"connectTimeout,omitempty"`

	// httpKeepAliveTimeout defines the maximum allowed time to wait for
	// a new HTTP request to appear on a connection from the client to the router.
	//
	// This field expects an unsigned duration string of a decimal number, with optional
	// fraction and a unit suffix, e.g. "300ms", "1.5s" or "2m45s".
	// Valid time units are "ms", "s", "m".
	// The allowed range is from 1 millisecond to 15 minutes.
	//
	// When omitted, this means the user has no opinion and the platform is left
	// to choose a reasonable default. This default is subject to change over time.
	// The current default is 300s.
	//
	// Low values (tens of milliseconds or less) can cause clients to close and reopen connections
	// for each request, leading to reduced connection sharing.
	// For HTTP/2, special care should be taken with low values.
	// A few seconds is a reasonable starting point to avoid holding idle connections open
	// while still allowing subsequent requests to reuse the connection.
	//
	// High values (minutes or more) favor connection reuse but may cause idle
	// connections to linger longer.
	//
	// +kubebuilder:validation:Type:=string
	// +kubebuilder:validation:XValidation:rule="self.matches('^([0-9]+(\\\\.[0-9]+)?(ms|s|m))+$')",message="httpKeepAliveTimeout must be a valid duration string composed of an unsigned integer value, optionally followed by a decimal fraction and a unit suffix (ms, s, m)"
	// +kubebuilder:validation:XValidation:rule="!self.matches('^([0-9]+(\\\\.[0-9]+)?(ms|s|m))+$') || duration(self) <= duration('15m')",message="httpKeepAliveTimeout must be less than or equal to 15 minutes"
	// +kubebuilder:validation:XValidation:rule="!self.matches('^([0-9]+(\\\\.[0-9]+)?(ms|s|m))+$') || duration(self) >= duration('1ms')",message="httpKeepAliveTimeout must be greater than or equal to 1 millisecond"
	// +kubebuilder:validation:MinLength=1
	// +kubebuilder:validation:MaxLength=16
	// +optional
	HTTPKeepAliveTimeout *metav1.Duration `json:"httpKeepAliveTimeout,omitempty"`

	// tlsInspectDelay defines how long the router can hold data to find a
	// matching route.
	//
	// Setting this too short can cause the router to fall back to the default
	// certificate for edge-terminated or reencrypt routes even when a better
	// matching certificate could be used.
	//
	// If unset, the default inspect delay is 5s
	// +kubebuilder:validation:Format=duration
	// +optional
	TLSInspectDelay *metav1.Duration `json:"tlsInspectDelay,omitempty"`

	// healthCheckInterval defines how long the router waits between two consecutive
	// health checks on its configured backends.  This value is applied globally as
	// a default for all routes, but may be overridden per-route by the route annotation
	// "router.openshift.io/haproxy.health.check.interval".
	//
	// Expects an unsigned duration string of decimal numbers, each with optional
	// fraction and a unit suffix, eg "300ms", "1.5h" or "2h45m".
	// Valid time units are "ns", "us" (or "µs" U+00B5 or "μs" U+03BC), "ms", "s", "m", "h".
	//
	// Setting this to less than 5s can cause excess traffic due to too frequent
	// TCP health checks and accompanying SYN packet storms.  Alternatively, setting
	// this too high can result in increased latency, due to backend servers that are no
	// longer available, but haven't yet been detected as such.
	//
	// An empty or zero healthCheckInterval means no opinion and IngressController chooses
	// a default, which is subject to change over time.
	// Currently the default healthCheckInterval value is 5s.
	//
	// Currently the minimum allowed value is 1s and the maximum allowed value is
	// 2147483647ms (24.85 days).  Both are subject to change over time.
	//
	// +kubebuilder:validation:Pattern=^(0|([0-9]+(\.[0-9]+)?(ns|us|µs|μs|ms|s|m|h))+)$
	// +kubebuilder:validation:Type:=string
	// +optional
	HealthCheckInterval *metav1.Duration `json:"healthCheckInterval,omitempty"`

	// maxConnections defines the maximum number of simultaneous
	// connections that can be established per HAProxy process.
	// Increasing this value allows each ingress controller pod to
	// handle more connections but at the cost of additional
	// system resources being consumed.
	//
	// Permitted values are: empty, 0, -1, and the range
	// 2000-2000000.
	//
	// If this field is empty or 0, the IngressController will use
	// the default value of 50000, but the default is subject to
	// change in future releases.
	//
	// If the value is -1 then HAProxy will dynamically compute a
	// maximum value based on the available ulimits in the running
	// container. Selecting -1 (i.e., auto) will result in a large
	// value being computed (~520000 on OpenShift >=4.10 clusters)
	// and therefore each HAProxy process will incur significant
	// memory usage compared to the current default of 50000.
	//
	// Setting a value that is greater than the current operating
	// system limit will prevent the HAProxy process from
	// starting.
	//
	// If you choose a discrete value (e.g., 750000) and the
	// router pod is migrated to a new node, there's no guarantee
	// that that new node has identical ulimits configured. In
	// such a scenario the pod would fail to start. If you have
	// nodes with different ulimits configured (e.g., different
	// tuned profiles) and you choose a discrete value then the
	// guidance is to use -1 and let the value be computed
	// dynamically at runtime.
	//
	// You can monitor memory usage for router containers with the
	// following metric:
	// 'container_memory_working_set_bytes{container="router",namespace="openshift-ingress"}'.
	//
	// You can monitor memory usage of individual HAProxy
	// processes in router containers with the following metric:
	// 'container_memory_working_set_bytes{container="router",namespace="openshift-ingress"}/container_processes{container="router",namespace="openshift-ingress"}'.
	//
	// +kubebuilder:validation:XValidation:rule="self == 0 || self == -1 || (self >= 2000 && self <= 2000000)",message="maxConnections must be 0, -1, or between 2000 and 2000000"
	// +optional
	MaxConnections int32 `json:"maxConnections,omitempty"`

	// reloadInterval defines the minimum interval at which the router is allowed to reload
	// to accept new changes. Increasing this value can prevent the accumulation of
	// HAProxy processes, depending on the scenario. Increasing this interval can
	// also lessen load imbalance on a backend's servers when using the roundrobin
	// balancing algorithm. Alternatively, decreasing this value may decrease latency
	// since updates to HAProxy's configuration can take effect more quickly.
	//
	// The value must be a time duration value; see <https://pkg.go.dev/time#ParseDuration>.
	// Currently, the minimum value allowed is 1s, and the maximum allowed value is
	// 120s. Minimum and maximum allowed values may change in future versions of OpenShift.
	// Note that if a duration outside of these bounds is provided, the value of reloadInterval
	// will be capped/floored and not rejected (e.g. a duration of over 120s will be capped to
	// 120s; the IngressController will not reject and replace this disallowed value with
	// the default).
	//
	// A zero value for reloadInterval tells the IngressController to choose the default,
	// which is currently 5s and subject to change without notice.
	//
	// This field expects an unsigned duration string of decimal numbers, each with optional
	// fraction and a unit suffix, e.g. "300ms", "1.5h" or "2h45m".
	// Valid time units are "ns", "us" (or "µs" U+00B5 or "μs" U+03BC), "ms", "s", "m", "h".
	//
	// Note: Setting a value significantly larger than the default of 5s can cause latency
	// in observing updates to routes and their endpoints. HAProxy's configuration will
	// be reloaded less frequently, and newly created routes will not be served until the
	// subsequent reload.
	//
	// +kubebuilder:validation:Pattern=^(0|([0-9]+(\.[0-9]+)?(ns|us|µs|μs|ms|s|m|h))+)$
	// +kubebuilder:validation:Type:=string
	// +optional
	ReloadInterval metav1.Duration `json:"reloadInterval,omitempty"`

	// configurationManagement specifies how OpenShift router should update
	// the HAProxy configuration.  The following values are valid for this
	// field:
	//
	// * "ForkAndReload".
	// * "Dynamic".
	//
	// Omitting this field means that the user has no opinion and the
	// platform may choose a reasonable default. This default is subject to
	// change over time.  The current default is "ForkAndReload".
	//
	// "ForkAndReload" means that OpenShift router should rewrite the
	// HAProxy configuration file and instruct HAProxy to fork and reload.
	// This is OpenShift router's traditional approach.
	//
	// "Dynamic" means that OpenShift router may use HAProxy's control
	// socket for some configuration updates and fall back to fork and
	// reload for other configuration updates.  This is a newer approach,
	// which may be less mature than ForkAndReload.  This setting can
	// improve load-balancing fairness and metrics accuracy and reduce CPU
	// and memory usage if HAProxy has frequent configuration updates for
	// route and endpoints updates.
	//
	// Note: The "Dynamic" option is currently experimental and should not
	// be enabled on production clusters.
	//
	// +openshift:enable:FeatureGate=IngressControllerDynamicConfigurationManager
	// +optional
	ConfigurationManagement IngressControllerConfigurationManagement `json:"configurationManagement,omitempty"`
}

// IngressControllerConfigurationManagement specifies whether always to use
// fork-and-reload to update the HAProxy configuration or whether to use
// HAProxy's control socket for some configuration updates.
//
// +enum
// +kubebuilder:validation:Enum=Dynamic;ForkAndReload
type IngressControllerConfigurationManagement string

const (
	IngressControllerConfigurationManagementDynamic       IngressControllerConfigurationManagement = "Dynamic"
	IngressControllerConfigurationManagementForkAndReload IngressControllerConfigurationManagement = "ForkAndReload"
)

// HTTPEmptyRequestsPolicy indicates how HTTP connections for which no request
// is received should be handled.
// +kubebuilder:validation:Enum=Respond;Ignore
type HTTPEmptyRequestsPolicy string

const (
	// HTTPEmptyRequestsPolicyRespond indicates that the ingress controller
	// should respond to empty requests.
	HTTPEmptyRequestsPolicyRespond HTTPEmptyRequestsPolicy = "Respond"
	// HTTPEmptyRequestsPolicyIgnore indicates that the ingress controller
	// should ignore empty requests.
	HTTPEmptyRequestsPolicyIgnore HTTPEmptyRequestsPolicy = "Ignore"
)

var (
	// Available indicates the ingress controller deployment is available.
	IngressControllerAvailableConditionType = "Available"
	// LoadBalancerManaged indicates the management status of any load balancer
	// service associated with an ingress controller.
	LoadBalancerManagedIngressConditionType = "LoadBalancerManaged"
	// LoadBalancerReady indicates the ready state of any load balancer service
	// associated with an ingress controller.
	LoadBalancerReadyIngressConditionType = "LoadBalancerReady"
	// DNSManaged indicates the management status of any DNS records for the
	// ingress controller.
	DNSManagedIngressConditionType = "DNSManaged"
	// DNSReady indicates the ready state of any DNS records for the ingress
	// controller.
	DNSReadyIngressConditionType = "DNSReady"
)

// IngressControllerStatus defines the observed status of the IngressController.
type IngressControllerStatus struct {
	// availableReplicas is number of observed available replicas according to the
	// ingress controller deployment.
	// +optional
	AvailableReplicas int32 `json:"availableReplicas"`

	// selector is a label selector, in string format, for ingress controller pods
	// corresponding to the IngressController. The number of matching pods should
	// equal the value of availableReplicas.
	// +optional
	Selector string `json:"selector"`

	// domain is the actual domain in use.
	// +optional
	Domain string `json:"domain"`

	// endpointPublishingStrategy is the actual strategy in use.
	// +optional
	EndpointPublishingStrategy *EndpointPublishingStrategy `json:"endpointPublishingStrategy,omitempty"`

	// conditions is a list of conditions and their status.
	//
	// Available means the ingress controller deployment is available and
	// servicing route and ingress resources (i.e, .status.availableReplicas
	// equals .spec.replicas)
	//
	// There are additional conditions which indicate the status of other
	// ingress controller features and capabilities.
	//
	//   * LoadBalancerManaged
	//   - True if the following conditions are met:
	//     * The endpoint publishing strategy requires a service load balancer.
	//   - False if any of those conditions are unsatisfied.
	//
	//   * LoadBalancerReady
	//   - True if the following conditions are met:
	//     * A load balancer is managed.
	//     * The load balancer is ready.
	//   - False if any of those conditions are unsatisfied.
	//
	//   * DNSManaged
	//   - True if the following conditions are met:
	//     * The endpoint publishing strategy and platform support DNS.
	//     * The ingress controller domain is set.
	//     * dns.config.openshift.io/cluster configures DNS zones.
	//   - False if any of those conditions are unsatisfied.
	//
	//   * DNSReady
	//   - True if the following conditions are met:
	//     * DNS is managed.
	//     * DNS records have been successfully created.
	//   - False if any of those conditions are unsatisfied.
	// +listType=map
	// +listMapKey=type
	// +optional
	Conditions []OperatorCondition `json:"conditions,omitempty"`

	// tlsProfile is the TLS connection configuration that is in effect.
	// +optional
	TLSProfile *configv1.TLSProfileSpec `json:"tlsProfile,omitempty"`

	// observedGeneration is the most recent generation observed.
	// +optional
	ObservedGeneration int64 `json:"observedGeneration,omitempty"`

	// namespaceSelector is the actual namespaceSelector in use.
	// +optional
	NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"`

	// routeSelector is the actual routeSelector in use.
	// +optional
	RouteSelector *metav1.LabelSelector `json:"routeSelector,omitempty"`

	// effectiveHAProxyVersion reports the HAProxy version currently in use by
	// this IngressController. This reflects the resolved value of the
	// spec.haproxyVersion field. When omitted, the effective value has not yet
	// been resolved by the operator or the feature is not enabled for this cluster.
	//
	// Examples for OpenShift 5.0:
	// - "3.2": Using HAProxy 3.2
	// - "2.8": Using HAProxy 2.8
	//
	// +optional
	// +openshift:enable:FeatureGate=IngressControllerMultipleHAProxyVersions
	EffectiveHAProxyVersion HAProxyVersion `json:"effectiveHAProxyVersion,omitempty"`
}

// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object

// IngressControllerList contains a list of IngressControllers.
//
// Compatibility level 1: Stable within a major release for a minimum of 12 months or 3 minor releases (whichever is longer).
// +openshift:compatibility-gen:level=1
type IngressControllerList struct {
	metav1.TypeMeta `json:",inline"`

	// metadata is the standard list's metadata.
	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
	metav1.ListMeta `json:"metadata,omitempty"`

	Items []IngressController `json:"items"`
}

// IngressControllerConnectionTerminationPolicy defines the behaviour
// for handling idle connections during a soft reload of the router.
//
// +kubebuilder:validation:Enum=Immediate;Deferred
type IngressControllerConnectionTerminationPolicy string

const (
	// IngressControllerConnectionTerminationPolicyImmediate specifies
	// that idle connections should be closed immediately during a
	// router reload.
	IngressControllerConnectionTerminationPolicyImmediate IngressControllerConnectionTerminationPolicy = "Immediate"

	// IngressControllerConnectionTerminationPolicyDeferred
	// specifies that idle connections should remain open until a
	// terminating event, such as a new request, the expiration of
	// the proxy keep-alive timeout, or the client closing the
	// connection.
	IngressControllerConnectionTerminationPolicyDeferred IngressControllerConnectionTerminationPolicy = "Deferred"
)

// IngressControllerClosedClientConnectionPolicy controls how the IngressController
// behaves when the client closes the TCP connection while the TLS
// handshake or HTTP request is in progress.
//
// +kubebuilder:validation:Enum=Abort;Continue
type IngressControllerClosedClientConnectionPolicy string

const (
	// IngressControllerClosedClientConnectionPolicyAbort aborts processing early when the client
	// closes the connection.
	//
	// This affects two types of processing: TLS handshake computation on the router
	// and request handling.
	//
	// When the client closes the connection, the router will stop processing
	// the TLS handshake, preventing unnecessary CPU work.
	//
	// If the HTTP request has not yet been sent to the backend, it will be aborted.
	// If the request is already being processed by the backend, the router will
	// half-close the connection to signal this condition to the backend server,
	// which can then decide how to proceed.
	IngressControllerClosedClientConnectionPolicyAbort IngressControllerClosedClientConnectionPolicy = "Abort"

	// IngressControllerClosedClientConnectionPolicyContinue continues processing even if the client
	// closes the connection.
	//
	// The router will complete the TLS handshake and wait for the backend
	// server's response regardless of the client having closed the connection.
	IngressControllerClosedClientConnectionPolicyContinue IngressControllerClosedClientConnectionPolicy = "Continue"
)

// HAProxyVersion is a string representing a HAProxy minor version in "X.Y"
// format. The allowed values are constrained by enum validation and vary by
// OpenShift release.
//
// +kubebuilder:validation:Enum="2.8";"3.2"
type HAProxyVersion string

const (
	// HAProxyVersion28 represents HAProxy 2.8, shipped with OpenShift 4.22.
	HAProxyVersion28 HAProxyVersion = "2.8"

	// HAProxyVersion32 represents HAProxy 3.2, introduced in OpenShift 5.0.
	HAProxyVersion32 HAProxyVersion = "3.2"
)
