diff --git a/api/v1alpha1/bindcluster_types.go b/api/v1alpha1/bindcluster_types.go index b224d51..6bb66e4 100644 --- a/api/v1alpha1/bindcluster_types.go +++ b/api/v1alpha1/bindcluster_types.go @@ -33,6 +33,13 @@ type ClusterServiceSpec struct { // +optional LoadBalancerIP string `json:"loadBalancerIP,omitempty"` + // ExternalTrafficPolicy for a LoadBalancer/NodePort Service. Local preserves + // client source IPs (required for source-IP ACLs on the DNS servers) but + // only routes to nodes running a pod. Defaults to Cluster. + // +kubebuilder:validation:Enum=Cluster;Local + // +optional + ExternalTrafficPolicy corev1.ServiceExternalTrafficPolicy `json:"externalTrafficPolicy,omitempty"` + // Annotations added to the client-facing Service (e.g. PureLB/MetalLB hints). // +optional Annotations map[string]string `json:"annotations,omitempty"` diff --git a/config/crd/bases/bind.unkin.net_bindclusters.yaml b/config/crd/bases/bind.unkin.net_bindclusters.yaml index c7d596e..7e595aa 100644 --- a/config/crd/bases/bind.unkin.net_bindclusters.yaml +++ b/config/crd/bases/bind.unkin.net_bindclusters.yaml @@ -1094,6 +1094,15 @@ spec: description: Annotations added to the client-facing Service (e.g. PureLB/MetalLB hints). type: object + externalTrafficPolicy: + description: |- + ExternalTrafficPolicy for a LoadBalancer/NodePort Service. Local preserves + client source IPs (required for source-IP ACLs on the DNS servers) but + only routes to nodes running a pod. Defaults to Cluster. + enum: + - Cluster + - Local + type: string loadBalancerIP: description: LoadBalancerIP requests a specific address when Type is LoadBalancer. diff --git a/config/crd/install.yaml b/config/crd/install.yaml index 469cff2..712be2f 100644 --- a/config/crd/install.yaml +++ b/config/crd/install.yaml @@ -1399,6 +1399,15 @@ spec: description: Annotations added to the client-facing Service (e.g. PureLB/MetalLB hints). type: object + externalTrafficPolicy: + description: |- + ExternalTrafficPolicy for a LoadBalancer/NodePort Service. Local preserves + client source IPs (required for source-IP ACLs on the DNS servers) but + only routes to nodes running a pod. Defaults to Cluster. + enum: + - Cluster + - Local + type: string loadBalancerIP: description: LoadBalancerIP requests a specific address when Type is LoadBalancer. diff --git a/internal/controller/bindcluster_controller.go b/internal/controller/bindcluster_controller.go index 178fab4..99e6300 100644 --- a/internal/controller/bindcluster_controller.go +++ b/internal/controller/bindcluster_controller.go @@ -273,6 +273,10 @@ func (r *BindClusterReconciler) reconcileServices(ctx context.Context, c *bindv1 LoadBalancerIP: c.Spec.Service.LoadBalancerIP, }, } + // externalTrafficPolicy is only valid for LoadBalancer/NodePort Services. + if svcType == corev1.ServiceTypeLoadBalancer || svcType == corev1.ServiceTypeNodePort { + client.Spec.ExternalTrafficPolicy = c.Spec.Service.ExternalTrafficPolicy + } return r.upsertService(ctx, c, client) } diff --git a/internal/controller/util.go b/internal/controller/util.go index e2b6905..12dccb8 100644 --- a/internal/controller/util.go +++ b/internal/controller/util.go @@ -57,6 +57,7 @@ func (r *BindClusterReconciler) upsertService(ctx context.Context, c *bindv1alph existing.Spec.Selector = desired.Spec.Selector existing.Spec.Type = desired.Spec.Type existing.Spec.LoadBalancerIP = desired.Spec.LoadBalancerIP + existing.Spec.ExternalTrafficPolicy = desired.Spec.ExternalTrafficPolicy if desired.Annotations != nil { if existing.Annotations == nil { existing.Annotations = map[string]string{}