diff --git a/.changes/unreleased/charts-redpanda-Added-20260326-per-listener-lb.yaml b/.changes/unreleased/charts-redpanda-Added-20260326-per-listener-lb.yaml new file mode 100644 index 000000000..b3bc2eaf2 --- /dev/null +++ b/.changes/unreleased/charts-redpanda-Added-20260326-per-listener-lb.yaml @@ -0,0 +1,4 @@ +project: charts/redpanda +kind: Added +body: Added per-listener LoadBalancer annotations support. When an external listener has `annotations` set, it gets a dedicated LoadBalancer Service per broker instead of sharing the default one. This enables use cases like private and public listeners on separate LBs with different cloud-provider annotations. +time: 2026-03-26T12:00:00.000000-04:00 diff --git a/charts/redpanda/chart/templates/_service.loadbalancer.go.tpl b/charts/redpanda/chart/templates/_service.loadbalancer.go.tpl index 4ed4e8a59..8627d8232 100644 --- a/charts/redpanda/chart/templates/_service.loadbalancer.go.tpl +++ b/charts/redpanda/chart/templates/_service.loadbalancer.go.tpl @@ -1,6 +1,215 @@ {{- /* GENERATED FILE DO NOT EDIT */ -}} {{- /* Transpiled by gotohelm from "github.com/redpanda-data/redpanda-operator/charts/redpanda/v25/service.loadbalancer.go" */ -}} +{{- define "redpanda.dedicatedListenerNames" -}} +{{- $listeners := (index .a 0) -}} +{{- range $_ := (list 1) -}} +{{- $_is_returning := false -}} +{{- $dedicated := (dict) -}} +{{- range $name, $l := $listeners.admin.external -}} +{{- if (get (fromJson (include "redpanda.ExternalListener.HasDedicatedService" (dict "a" (list $l)))) "r") -}} +{{- $_ := (set $dedicated $name true) -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- range $name, $l := $listeners.kafka.external -}} +{{- if (get (fromJson (include "redpanda.ExternalListener.HasDedicatedService" (dict "a" (list $l)))) "r") -}} +{{- $_ := (set $dedicated $name true) -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- range $name, $l := $listeners.http.external -}} +{{- if (get (fromJson (include "redpanda.ExternalListener.HasDedicatedService" (dict "a" (list $l)))) "r") -}} +{{- $_ := (set $dedicated $name true) -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- range $name, $l := $listeners.schemaRegistry.external -}} +{{- if (get (fromJson (include "redpanda.ExternalListener.HasDedicatedService" (dict "a" (list $l)))) "r") -}} +{{- $_ := (set $dedicated $name true) -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- $_is_returning = true -}} +{{- (dict "r" $dedicated) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} + +{{- define "redpanda.dedicatedListenerAnnotations" -}} +{{- $listeners := (index .a 0) -}} +{{- $listenerName := (index .a 1) -}} +{{- range $_ := (list 1) -}} +{{- $_is_returning := false -}} +{{- $merged := (dict) -}} +{{- range $name, $l := $listeners.admin.external -}} +{{- if (eq $name $listenerName) -}} +{{- range $k, $v := $l.annotations -}} +{{- $_ := (set $merged $k $v) -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- range $name, $l := $listeners.kafka.external -}} +{{- if (eq $name $listenerName) -}} +{{- range $k, $v := $l.annotations -}} +{{- $_ := (set $merged $k $v) -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- range $name, $l := $listeners.http.external -}} +{{- if (eq $name $listenerName) -}} +{{- range $k, $v := $l.annotations -}} +{{- $_ := (set $merged $k $v) -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- range $name, $l := $listeners.schemaRegistry.external -}} +{{- if (eq $name $listenerName) -}} +{{- range $k, $v := $l.annotations -}} +{{- $_ := (set $merged $k $v) -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- $_is_returning = true -}} +{{- (dict "r" $merged) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} + +{{- define "redpanda.dedicatedListenerSourceRanges" -}} +{{- $listeners := (index .a 0) -}} +{{- $listenerName := (index .a 1) -}} +{{- range $_ := (list 1) -}} +{{- $_is_returning := false -}} +{{- range $name, $l := $listeners.kafka.external -}} +{{- if (and (eq $name $listenerName) (gt ((get (fromJson (include "_shims.len" (dict "a" (list $l.loadBalancerSourceRanges)))) "r") | int) (0 | int))) -}} +{{- $_is_returning = true -}} +{{- (dict "r" $l.loadBalancerSourceRanges) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- range $name, $l := $listeners.admin.external -}} +{{- if (and (eq $name $listenerName) (gt ((get (fromJson (include "_shims.len" (dict "a" (list $l.loadBalancerSourceRanges)))) "r") | int) (0 | int))) -}} +{{- $_is_returning = true -}} +{{- (dict "r" $l.loadBalancerSourceRanges) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- range $name, $l := $listeners.http.external -}} +{{- if (and (eq $name $listenerName) (gt ((get (fromJson (include "_shims.len" (dict "a" (list $l.loadBalancerSourceRanges)))) "r") | int) (0 | int))) -}} +{{- $_is_returning = true -}} +{{- (dict "r" $l.loadBalancerSourceRanges) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- range $name, $l := $listeners.schemaRegistry.external -}} +{{- if (and (eq $name $listenerName) (gt ((get (fromJson (include "_shims.len" (dict "a" (list $l.loadBalancerSourceRanges)))) "r") | int) (0 | int))) -}} +{{- $_is_returning = true -}} +{{- (dict "r" $l.loadBalancerSourceRanges) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- $_is_returning = true -}} +{{- (dict "r" (coalesce nil)) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} + +{{- define "redpanda.dedicatedListenerServiceType" -}} +{{- $listeners := (index .a 0) -}} +{{- $listenerName := (index .a 1) -}} +{{- range $_ := (list 1) -}} +{{- $_is_returning := false -}} +{{- range $name, $l := $listeners.kafka.external -}} +{{- if (and (eq $name $listenerName) (ne (toJson $l.type) "null")) -}} +{{- $_is_returning = true -}} +{{- (dict "r" $l.type) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- range $name, $l := $listeners.admin.external -}} +{{- if (and (eq $name $listenerName) (ne (toJson $l.type) "null")) -}} +{{- $_is_returning = true -}} +{{- (dict "r" $l.type) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- range $name, $l := $listeners.http.external -}} +{{- if (and (eq $name $listenerName) (ne (toJson $l.type) "null")) -}} +{{- $_is_returning = true -}} +{{- (dict "r" $l.type) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- range $name, $l := $listeners.schemaRegistry.external -}} +{{- if (and (eq $name $listenerName) (ne (toJson $l.type) "null")) -}} +{{- $_is_returning = true -}} +{{- (dict "r" $l.type) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- $_is_returning = true -}} +{{- (dict "r" "LoadBalancer") | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} + {{- define "redpanda.LoadBalancerServices" -}} {{- $state := (index .a 0) -}} {{- range $_ := (list 1) -}} @@ -27,6 +236,7 @@ {{- if $_is_returning -}} {{- break -}} {{- end -}} +{{- $dedicated := (get (fromJson (include "redpanda.dedicatedListenerNames" (dict "a" (list $state.Values.listeners)))) "r") -}} {{- range $i, $podname := $pods -}} {{- $annotations := (dict) -}} {{- range $k, $v := $state.Values.external.annotations -}} @@ -56,13 +266,39 @@ {{- end -}} {{- $_ := (set $podSelector "statefulset.kubernetes.io/pod-name" $podname) -}} {{- $ports := (coalesce nil) -}} -{{- $ports = (concat (default (list) $ports) (default (list) (get (fromJson (include "redpanda.ListenerConfig.ServicePorts" (dict "a" (list $state.Values.listeners.admin "admin" $state.Values.external)))) "r"))) -}} -{{- $ports = (concat (default (list) $ports) (default (list) (get (fromJson (include "redpanda.ListenerConfig.ServicePorts" (dict "a" (list $state.Values.listeners.kafka "kafka" $state.Values.external)))) "r"))) -}} -{{- $ports = (concat (default (list) $ports) (default (list) (get (fromJson (include "redpanda.ListenerConfig.ServicePorts" (dict "a" (list $state.Values.listeners.http "http" $state.Values.external)))) "r"))) -}} -{{- $ports = (concat (default (list) $ports) (default (list) (get (fromJson (include "redpanda.ListenerConfig.ServicePorts" (dict "a" (list $state.Values.listeners.schemaRegistry "schema" $state.Values.external)))) "r"))) -}} +{{- $ports = (concat (default (list) $ports) (default (list) (get (fromJson (include "redpanda.ListenerConfig.ServicePortsExcludingListeners" (dict "a" (list $state.Values.listeners.admin "admin" $state.Values.external $dedicated)))) "r"))) -}} +{{- $ports = (concat (default (list) $ports) (default (list) (get (fromJson (include "redpanda.ListenerConfig.ServicePortsExcludingListeners" (dict "a" (list $state.Values.listeners.kafka "kafka" $state.Values.external $dedicated)))) "r"))) -}} +{{- $ports = (concat (default (list) $ports) (default (list) (get (fromJson (include "redpanda.ListenerConfig.ServicePortsExcludingListeners" (dict "a" (list $state.Values.listeners.http "http" $state.Values.external $dedicated)))) "r"))) -}} +{{- $ports = (concat (default (list) $ports) (default (list) (get (fromJson (include "redpanda.ListenerConfig.ServicePortsExcludingListeners" (dict "a" (list $state.Values.listeners.schemaRegistry "schema" $state.Values.external $dedicated)))) "r"))) -}} +{{- if (gt ((get (fromJson (include "_shims.len" (dict "a" (list $ports)))) "r") | int) (0 | int)) -}} {{- $svc := (mustMergeOverwrite (dict "metadata" (dict) "spec" (dict) "status" (dict "loadBalancer" (dict))) (mustMergeOverwrite (dict) (dict "apiVersion" "v1" "kind" "Service")) (dict "metadata" (mustMergeOverwrite (dict) (dict "name" (printf "lb-%s" $podname) "namespace" $state.Release.Namespace "labels" $labels "annotations" $annotations)) "spec" (mustMergeOverwrite (dict) (dict "externalTrafficPolicy" "Local" "loadBalancerSourceRanges" $state.Values.external.sourceRanges "ports" $ports "publishNotReadyAddresses" true "selector" $podSelector "sessionAffinity" "None" "type" "LoadBalancer")))) -}} {{- $services = (concat (default (list) $services) (list $svc)) -}} {{- end -}} +{{- range $listenerName, $_ := $dedicated -}} +{{- $dedicatedPorts := (coalesce nil) -}} +{{- $dedicatedPorts = (concat (default (list) $dedicatedPorts) (default (list) (get (fromJson (include "redpanda.ListenerConfig.ServicePortsForListener" (dict "a" (list $state.Values.listeners.admin "admin" $listenerName $state.Values.external)))) "r"))) -}} +{{- $dedicatedPorts = (concat (default (list) $dedicatedPorts) (default (list) (get (fromJson (include "redpanda.ListenerConfig.ServicePortsForListener" (dict "a" (list $state.Values.listeners.kafka "kafka" $listenerName $state.Values.external)))) "r"))) -}} +{{- $dedicatedPorts = (concat (default (list) $dedicatedPorts) (default (list) (get (fromJson (include "redpanda.ListenerConfig.ServicePortsForListener" (dict "a" (list $state.Values.listeners.http "http" $listenerName $state.Values.external)))) "r"))) -}} +{{- $dedicatedPorts = (concat (default (list) $dedicatedPorts) (default (list) (get (fromJson (include "redpanda.ListenerConfig.ServicePortsForListener" (dict "a" (list $state.Values.listeners.schemaRegistry "schema" $listenerName $state.Values.external)))) "r"))) -}} +{{- if (eq ((get (fromJson (include "_shims.len" (dict "a" (list $dedicatedPorts)))) "r") | int) (0 | int)) -}} +{{- continue -}} +{{- end -}} +{{- $dedicatedAnnotations := (dict) -}} +{{- range $k, $v := (get (fromJson (include "redpanda.dedicatedListenerAnnotations" (dict "a" (list $state.Values.listeners $listenerName)))) "r") -}} +{{- $_ := (set $dedicatedAnnotations $k $v) -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- $svcType := (get (fromJson (include "redpanda.dedicatedListenerServiceType" (dict "a" (list $state.Values.listeners $listenerName)))) "r") -}} +{{- $sourceRanges := (get (fromJson (include "redpanda.dedicatedListenerSourceRanges" (dict "a" (list $state.Values.listeners $listenerName)))) "r") -}} +{{- $svc := (mustMergeOverwrite (dict "metadata" (dict) "spec" (dict) "status" (dict "loadBalancer" (dict))) (mustMergeOverwrite (dict) (dict "apiVersion" "v1" "kind" "Service")) (dict "metadata" (mustMergeOverwrite (dict) (dict "name" (printf "lb-%s-%s" $listenerName $podname) "namespace" $state.Release.Namespace "labels" $labels "annotations" $dedicatedAnnotations)) "spec" (mustMergeOverwrite (dict) (dict "externalTrafficPolicy" "Local" "loadBalancerSourceRanges" $sourceRanges "ports" $dedicatedPorts "publishNotReadyAddresses" true "selector" $podSelector "sessionAffinity" "None" "type" $svcType)))) -}} +{{- $services = (concat (default (list) $services) (list $svc)) -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- end -}} {{- if $_is_returning -}} {{- break -}} {{- end -}} diff --git a/charts/redpanda/chart/templates/_values.go.tpl b/charts/redpanda/chart/templates/_values.go.tpl index 818f2a1a6..bdbf68368 100644 --- a/charts/redpanda/chart/templates/_values.go.tpl +++ b/charts/redpanda/chart/templates/_values.go.tpl @@ -1192,6 +1192,60 @@ {{- end -}} {{- end -}} +{{- define "redpanda.ListenerConfig.ServicePortsForListener" -}} +{{- $l := (index .a 0) -}} +{{- $namePrefix := (index .a 1) -}} +{{- $listenerName := (index .a 2) -}} +{{- $external := (index .a 3) -}} +{{- range $_ := (list 1) -}} +{{- $_is_returning := false -}} +{{- $ports := (coalesce nil) -}} +{{- range $name, $listener := $l.external -}} +{{- if (ne $name $listenerName) -}} +{{- continue -}} +{{- end -}} +{{- if (not (get (fromJson (include "_shims.ptr_Deref" (dict "a" (list $listener.enabled $external.enabled)))) "r")) -}} +{{- continue -}} +{{- end -}} +{{- $fallbackPorts := (concat (default (list) $listener.advertisedPorts) (list ($l.port | int))) -}} +{{- $ports = (concat (default (list) $ports) (list (mustMergeOverwrite (dict "port" 0 "targetPort" 0) (dict "name" (printf "%s-%s" $namePrefix $name) "protocol" "TCP" "appProtocol" $l.appProtocol "targetPort" ($listener.port | int) "port" ((get (fromJson (include "_shims.ptr_Deref" (dict "a" (list $listener.nodePort (index $fallbackPorts (0 | int)))))) "r") | int))))) -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- $_is_returning = true -}} +{{- (dict "r" $ports) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} + +{{- define "redpanda.ListenerConfig.ServicePortsExcludingListeners" -}} +{{- $l := (index .a 0) -}} +{{- $namePrefix := (index .a 1) -}} +{{- $external := (index .a 2) -}} +{{- $exclude := (index .a 3) -}} +{{- range $_ := (list 1) -}} +{{- $_is_returning := false -}} +{{- $ports := (coalesce nil) -}} +{{- range $name, $listener := $l.external -}} +{{- if (ternary (index $exclude $name) false (hasKey $exclude $name)) -}} +{{- continue -}} +{{- end -}} +{{- if (not (get (fromJson (include "_shims.ptr_Deref" (dict "a" (list $listener.enabled $external.enabled)))) "r")) -}} +{{- continue -}} +{{- end -}} +{{- $fallbackPorts := (concat (default (list) $listener.advertisedPorts) (list ($l.port | int))) -}} +{{- $ports = (concat (default (list) $ports) (list (mustMergeOverwrite (dict "port" 0 "targetPort" 0) (dict "name" (printf "%s-%s" $namePrefix $name) "protocol" "TCP" "appProtocol" $l.appProtocol "targetPort" ($listener.port | int) "port" ((get (fromJson (include "_shims.ptr_Deref" (dict "a" (list $listener.nodePort (index $fallbackPorts (0 | int)))))) "r") | int))))) -}} +{{- end -}} +{{- if $_is_returning -}} +{{- break -}} +{{- end -}} +{{- $_is_returning = true -}} +{{- (dict "r" $ports) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} + {{- define "redpanda.ListenerConfig.TrustStores" -}} {{- $l := (index .a 0) -}} {{- $tls := (index .a 1) -}} @@ -1276,6 +1330,16 @@ {{- end -}} {{- end -}} +{{- define "redpanda.ExternalListener.HasDedicatedService" -}} +{{- $l := (index .a 0) -}} +{{- range $_ := (list 1) -}} +{{- $_is_returning := false -}} +{{- $_is_returning = true -}} +{{- (dict "r" (ne (toJson $l.type) "null")) | toJson -}} +{{- break -}} +{{- end -}} +{{- end -}} + {{- define "redpanda.ExternalListener.AsString" -}} {{- $l := (index .a 0) -}} {{- range $_ := (list 1) -}} @@ -1286,7 +1350,7 @@ {{- $auth = $authAStr -}} {{- end -}} {{- $_is_returning = true -}} -{{- (dict "r" (mustMergeOverwrite (dict "enabled" (coalesce nil) "advertisedPorts" (coalesce nil) "port" 0 "nodePort" (coalesce nil) "tls" (coalesce nil)) (dict "enabled" $l.enabled "advertisedPorts" $l.advertisedPorts "port" ($l.port | int) "nodePort" $l.nodePort "tls" $l.tls "authenticationMethod" $auth "prefixTemplate" $l.prefixTemplate))) | toJson -}} +{{- (dict "r" (mustMergeOverwrite (dict "enabled" (coalesce nil) "advertisedPorts" (coalesce nil) "port" 0 "nodePort" (coalesce nil) "tls" (coalesce nil)) (dict "enabled" $l.enabled "advertisedPorts" $l.advertisedPorts "port" ($l.port | int) "nodePort" $l.nodePort "tls" $l.tls "authenticationMethod" $auth "prefixTemplate" $l.prefixTemplate "type" $l.type "annotations" $l.annotations "loadBalancerSourceRanges" $l.loadBalancerSourceRanges))) | toJson -}} {{- break -}} {{- end -}} {{- end -}} @@ -1332,9 +1396,9 @@ {{- $result := (dict) -}} {{- range $k, $v := $c -}} {{- if (not (empty $v)) -}} -{{- $_1845___ok_15 := (get (fromJson (include "_shims.asnumeric" (dict "a" (list $v)))) "r") -}} -{{- $_ := ((index $_1845___ok_15 0) | float64) -}} -{{- $ok_15 := (index $_1845___ok_15 1) -}} +{{- $_1921___ok_15 := (get (fromJson (include "_shims.asnumeric" (dict "a" (list $v)))) "r") -}} +{{- $_ := ((index $_1921___ok_15 0) | float64) -}} +{{- $ok_15 := (index $_1921___ok_15 1) -}} {{- if $ok_15 -}} {{- $_ := (set $result $k $v) -}} {{- else -}}{{- if (kindIs "bool" $v) -}} @@ -1360,9 +1424,9 @@ {{- $_is_returning := false -}} {{- $result := (dict) -}} {{- range $k, $v := $c -}} -{{- $_1865_b_16_ok_17 := (get (fromJson (include "_shims.typetest" (dict "a" (list "bool" $v false)))) "r") -}} -{{- $b_16 := (index $_1865_b_16_ok_17 0) -}} -{{- $ok_17 := (index $_1865_b_16_ok_17 1) -}} +{{- $_1941_b_16_ok_17 := (get (fromJson (include "_shims.typetest" (dict "a" (list "bool" $v false)))) "r") -}} +{{- $b_16 := (index $_1941_b_16_ok_17 0) -}} +{{- $ok_17 := (index $_1941_b_16_ok_17 1) -}} {{- if $ok_17 -}} {{- $_ := (set $result $k $b_16) -}} {{- continue -}} @@ -1405,15 +1469,15 @@ {{- $config := (index .a 1) -}} {{- range $_ := (list 1) -}} {{- $_is_returning := false -}} -{{- $_1910___hasAccessKey := (get (fromJson (include "_shims.dicttest" (dict "a" (list $config "cloud_storage_access_key" (coalesce nil))))) "r") -}} -{{- $_ := (index $_1910___hasAccessKey 0) -}} -{{- $hasAccessKey := (index $_1910___hasAccessKey 1) -}} -{{- $_1911___hasSecretKey := (get (fromJson (include "_shims.dicttest" (dict "a" (list $config "cloud_storage_secret_key" (coalesce nil))))) "r") -}} -{{- $_ := (index $_1911___hasSecretKey 0) -}} -{{- $hasSecretKey := (index $_1911___hasSecretKey 1) -}} -{{- $_1912___hasSharedKey := (get (fromJson (include "_shims.dicttest" (dict "a" (list $config "cloud_storage_azure_shared_key" (coalesce nil))))) "r") -}} -{{- $_ := (index $_1912___hasSharedKey 0) -}} -{{- $hasSharedKey := (index $_1912___hasSharedKey 1) -}} +{{- $_1986___hasAccessKey := (get (fromJson (include "_shims.dicttest" (dict "a" (list $config "cloud_storage_access_key" (coalesce nil))))) "r") -}} +{{- $_ := (index $_1986___hasAccessKey 0) -}} +{{- $hasAccessKey := (index $_1986___hasAccessKey 1) -}} +{{- $_1987___hasSecretKey := (get (fromJson (include "_shims.dicttest" (dict "a" (list $config "cloud_storage_secret_key" (coalesce nil))))) "r") -}} +{{- $_ := (index $_1987___hasSecretKey 0) -}} +{{- $hasSecretKey := (index $_1987___hasSecretKey 1) -}} +{{- $_1988___hasSharedKey := (get (fromJson (include "_shims.dicttest" (dict "a" (list $config "cloud_storage_azure_shared_key" (coalesce nil))))) "r") -}} +{{- $_ := (index $_1988___hasSharedKey 0) -}} +{{- $hasSharedKey := (index $_1988___hasSharedKey 1) -}} {{- $envvars := (coalesce nil) -}} {{- if (and (not $hasAccessKey) (get (fromJson (include "redpanda.SecretRef.IsValid" (dict "a" (list $tsc.accessKey)))) "r")) -}} {{- $envvars = (concat (default (list) $envvars) (list (mustMergeOverwrite (dict "name" "") (dict "name" "REDPANDA_CLOUD_STORAGE_ACCESS_KEY" "valueFrom" (get (fromJson (include "redpanda.SecretRef.AsSource" (dict "a" (list $tsc.accessKey)))) "r"))))) -}} @@ -1436,12 +1500,12 @@ {{- $c := (index .a 0) -}} {{- range $_ := (list 1) -}} {{- $_is_returning := false -}} -{{- $_1948___containerExists := (get (fromJson (include "_shims.dicttest" (dict "a" (list $c "cloud_storage_azure_container" (coalesce nil))))) "r") -}} -{{- $_ := (index $_1948___containerExists 0) -}} -{{- $containerExists := (index $_1948___containerExists 1) -}} -{{- $_1949___accountExists := (get (fromJson (include "_shims.dicttest" (dict "a" (list $c "cloud_storage_azure_storage_account" (coalesce nil))))) "r") -}} -{{- $_ := (index $_1949___accountExists 0) -}} -{{- $accountExists := (index $_1949___accountExists 1) -}} +{{- $_2024___containerExists := (get (fromJson (include "_shims.dicttest" (dict "a" (list $c "cloud_storage_azure_container" (coalesce nil))))) "r") -}} +{{- $_ := (index $_2024___containerExists 0) -}} +{{- $containerExists := (index $_2024___containerExists 1) -}} +{{- $_2025___accountExists := (get (fromJson (include "_shims.dicttest" (dict "a" (list $c "cloud_storage_azure_storage_account" (coalesce nil))))) "r") -}} +{{- $_ := (index $_2025___accountExists 0) -}} +{{- $accountExists := (index $_2025___accountExists 1) -}} {{- $_is_returning = true -}} {{- (dict "r" (and $containerExists $accountExists)) | toJson -}} {{- break -}} @@ -1452,9 +1516,9 @@ {{- $c := (index .a 0) -}} {{- range $_ := (list 1) -}} {{- $_is_returning := false -}} -{{- $_1954_value_ok := (get (fromJson (include "_shims.dicttest" (dict "a" (list $c `cloud_storage_cache_size` (coalesce nil))))) "r") -}} -{{- $value := (index $_1954_value_ok 0) -}} -{{- $ok := (index $_1954_value_ok 1) -}} +{{- $_2030_value_ok := (get (fromJson (include "_shims.dicttest" (dict "a" (list $c `cloud_storage_cache_size` (coalesce nil))))) "r") -}} +{{- $value := (index $_2030_value_ok 0) -}} +{{- $ok := (index $_2030_value_ok 1) -}} {{- if (not $ok) -}} {{- $_is_returning = true -}} {{- (dict "r" (coalesce nil)) | toJson -}} diff --git a/charts/redpanda/chart/values.schema.json b/charts/redpanda/chart/values.schema.json index 64e0b0ce1..99f03d0c5 100644 --- a/charts/redpanda/chart/values.schema.json +++ b/charts/redpanda/chart/values.schema.json @@ -4631,6 +4631,12 @@ "minItems": 1, "type": "array" }, + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, "authenticationMethod": { "oneOf": [ { @@ -4644,6 +4650,12 @@ "enabled": { "type": "boolean" }, + "loadBalancerSourceRanges": { + "items": { + "type": "string" + }, + "type": "array" + }, "nodePort": { "type": "integer" }, @@ -4705,6 +4717,10 @@ } }, "type": "object" + }, + "type": { + "pattern": "^(LoadBalancer|NodePort)$", + "type": "string" } }, "required": [ @@ -4818,6 +4834,12 @@ "minItems": 1, "type": "array" }, + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, "authenticationMethod": { "oneOf": [ { @@ -4835,6 +4857,12 @@ "enabled": { "type": "boolean" }, + "loadBalancerSourceRanges": { + "items": { + "type": "string" + }, + "type": "array" + }, "nodePort": { "type": "integer" }, @@ -4896,6 +4924,10 @@ } }, "type": "object" + }, + "type": { + "pattern": "^(LoadBalancer|NodePort)$", + "type": "string" } }, "required": [ @@ -5010,6 +5042,12 @@ "minItems": 1, "type": "array" }, + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, "authenticationMethod": { "oneOf": [ { @@ -5028,6 +5066,12 @@ "enabled": { "type": "boolean" }, + "loadBalancerSourceRanges": { + "items": { + "type": "string" + }, + "type": "array" + }, "nodePort": { "type": "integer" }, @@ -5089,6 +5133,10 @@ } }, "type": "object" + }, + "type": { + "pattern": "^(LoadBalancer|NodePort)$", + "type": "string" } }, "required": [ @@ -5268,6 +5316,12 @@ "minItems": 1, "type": "array" }, + "annotations": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, "authenticationMethod": { "oneOf": [ { @@ -5281,6 +5335,12 @@ "enabled": { "type": "boolean" }, + "loadBalancerSourceRanges": { + "items": { + "type": "string" + }, + "type": "array" + }, "nodePort": { "type": "integer" }, @@ -5342,6 +5402,10 @@ } }, "type": "object" + }, + "type": { + "pattern": "^(LoadBalancer|NodePort)$", + "type": "string" } }, "required": [ diff --git a/charts/redpanda/service.loadbalancer.go b/charts/redpanda/service.loadbalancer.go index bf5fca8a8..2fc99a395 100644 --- a/charts/redpanda/service.loadbalancer.go +++ b/charts/redpanda/service.loadbalancer.go @@ -20,6 +20,123 @@ import ( "github.com/redpanda-data/redpanda-operator/gotohelm/helmette" ) +// dedicatedListenerNames returns the set of external listener names that have +// a per-listener Type configured on any protocol. These listeners will get +// their own dedicated Service per broker instead of sharing the default one. +func dedicatedListenerNames(listeners *Listeners) map[string]bool { + dedicated := map[string]bool{} + for name, l := range helmette.SortedMap(listeners.Admin.External) { + if l.HasDedicatedService() { + dedicated[name] = true + } + } + for name, l := range helmette.SortedMap(listeners.Kafka.External) { + if l.HasDedicatedService() { + dedicated[name] = true + } + } + for name, l := range helmette.SortedMap(listeners.HTTP.External) { + if l.HasDedicatedService() { + dedicated[name] = true + } + } + for name, l := range helmette.SortedMap(listeners.SchemaRegistry.External) { + if l.HasDedicatedService() { + dedicated[name] = true + } + } + return dedicated +} + +// dedicatedListenerAnnotations returns the merged annotations for a named +// listener across all protocols. If multiple protocols define annotations for +// the same listener name, they are merged (last write wins for duplicate keys). +func dedicatedListenerAnnotations(listeners *Listeners, listenerName string) map[string]string { + merged := map[string]string{} + for name, l := range helmette.SortedMap(listeners.Admin.External) { + if name == listenerName { + for k, v := range helmette.SortedMap(l.Annotations) { + merged[k] = v + } + } + } + for name, l := range helmette.SortedMap(listeners.Kafka.External) { + if name == listenerName { + for k, v := range helmette.SortedMap(l.Annotations) { + merged[k] = v + } + } + } + for name, l := range helmette.SortedMap(listeners.HTTP.External) { + if name == listenerName { + for k, v := range helmette.SortedMap(l.Annotations) { + merged[k] = v + } + } + } + for name, l := range helmette.SortedMap(listeners.SchemaRegistry.External) { + if name == listenerName { + for k, v := range helmette.SortedMap(l.Annotations) { + merged[k] = v + } + } + } + return merged +} + +// dedicatedListenerSourceRanges returns the LoadBalancerSourceRanges for a named +// listener. Uses the first non-empty value found across protocols. +func dedicatedListenerSourceRanges(listeners *Listeners, listenerName string) []string { + for name, l := range helmette.SortedMap(listeners.Kafka.External) { + if name == listenerName && len(l.LoadBalancerSourceRanges) > 0 { + return l.LoadBalancerSourceRanges + } + } + for name, l := range helmette.SortedMap(listeners.Admin.External) { + if name == listenerName && len(l.LoadBalancerSourceRanges) > 0 { + return l.LoadBalancerSourceRanges + } + } + for name, l := range helmette.SortedMap(listeners.HTTP.External) { + if name == listenerName && len(l.LoadBalancerSourceRanges) > 0 { + return l.LoadBalancerSourceRanges + } + } + for name, l := range helmette.SortedMap(listeners.SchemaRegistry.External) { + if name == listenerName && len(l.LoadBalancerSourceRanges) > 0 { + return l.LoadBalancerSourceRanges + } + } + return nil +} + +// dedicatedListenerServiceType returns the Service type for a named listener. +// Uses the first non-nil Type found across protocols. +func dedicatedListenerServiceType(listeners *Listeners, listenerName string) corev1.ServiceType { + for name, l := range helmette.SortedMap(listeners.Kafka.External) { + if name == listenerName && l.Type != nil { + return *l.Type + } + } + for name, l := range helmette.SortedMap(listeners.Admin.External) { + if name == listenerName && l.Type != nil { + return *l.Type + } + } + for name, l := range helmette.SortedMap(listeners.HTTP.External) { + if name == listenerName && l.Type != nil { + return *l.Type + } + } + for name, l := range helmette.SortedMap(listeners.SchemaRegistry.External) { + if name == listenerName && l.Type != nil { + return *l.Type + } + } + // Fallback to LoadBalancer if somehow we get here. + return corev1.ServiceTypeLoadBalancer +} + func LoadBalancerServices(state *RenderState) []*corev1.Service { // This is technically a divergence from previous behavior but this matches // the NodePort's check and is more reasonable. @@ -47,6 +164,9 @@ func LoadBalancerServices(state *RenderState) []*corev1.Service { pods = append(pods, PodNames(state, set)...) } + // Identify listeners that should get their own dedicated Service. + dedicated := dedicatedListenerNames(&state.Values.Listeners) + for i, podname := range pods { // NB: A range loop is used here as its the most terse way to handle // nil maps in gotohelm. @@ -81,38 +201,84 @@ func LoadBalancerServices(state *RenderState) []*corev1.Service { podSelector["statefulset.kubernetes.io/pod-name"] = podname - // Divergences pop up here due to iterating over a map. This isn't okay - // in helm. TODO setup a linter that barks about this? Also a helper - // for getting the sorted keys of a map? + // Default shared LB: includes all listeners that do NOT have a dedicated Service type. var ports []corev1.ServicePort - ports = append(ports, state.Values.Listeners.Admin.ServicePorts("admin", &state.Values.External)...) - ports = append(ports, state.Values.Listeners.Kafka.ServicePorts("kafka", &state.Values.External)...) - ports = append(ports, state.Values.Listeners.HTTP.ServicePorts("http", &state.Values.External)...) - ports = append(ports, state.Values.Listeners.SchemaRegistry.ServicePorts("schema", &state.Values.External)...) - - svc := &corev1.Service{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "Service", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: fmt.Sprintf("lb-%s", podname), - Namespace: state.Release.Namespace, - Labels: labels, - Annotations: annotations, - }, - Spec: corev1.ServiceSpec{ - ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyLocal, - LoadBalancerSourceRanges: state.Values.External.SourceRanges, - Ports: ports, - PublishNotReadyAddresses: true, - Selector: podSelector, - SessionAffinity: corev1.ServiceAffinityNone, - Type: corev1.ServiceTypeLoadBalancer, - }, - } - - services = append(services, svc) + ports = append(ports, state.Values.Listeners.Admin.ServicePortsExcludingListeners("admin", &state.Values.External, dedicated)...) + ports = append(ports, state.Values.Listeners.Kafka.ServicePortsExcludingListeners("kafka", &state.Values.External, dedicated)...) + ports = append(ports, state.Values.Listeners.HTTP.ServicePortsExcludingListeners("http", &state.Values.External, dedicated)...) + ports = append(ports, state.Values.Listeners.SchemaRegistry.ServicePortsExcludingListeners("schema", &state.Values.External, dedicated)...) + + // Only create the shared LB if it has ports remaining. + if len(ports) > 0 { + svc := &corev1.Service{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Service", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("lb-%s", podname), + Namespace: state.Release.Namespace, + Labels: labels, + Annotations: annotations, + }, + Spec: corev1.ServiceSpec{ + ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyLocal, + LoadBalancerSourceRanges: state.Values.External.SourceRanges, + Ports: ports, + PublishNotReadyAddresses: true, + Selector: podSelector, + SessionAffinity: corev1.ServiceAffinityNone, + Type: corev1.ServiceTypeLoadBalancer, + }, + } + + services = append(services, svc) + } + + // Dedicated Services: one per listener name that has a Type set. + for listenerName := range helmette.SortedMap(dedicated) { + var dedicatedPorts []corev1.ServicePort + dedicatedPorts = append(dedicatedPorts, state.Values.Listeners.Admin.ServicePortsForListener("admin", listenerName, &state.Values.External)...) + dedicatedPorts = append(dedicatedPorts, state.Values.Listeners.Kafka.ServicePortsForListener("kafka", listenerName, &state.Values.External)...) + dedicatedPorts = append(dedicatedPorts, state.Values.Listeners.HTTP.ServicePortsForListener("http", listenerName, &state.Values.External)...) + dedicatedPorts = append(dedicatedPorts, state.Values.Listeners.SchemaRegistry.ServicePortsForListener("schema", listenerName, &state.Values.External)...) + + if len(dedicatedPorts) == 0 { + continue + } + + dedicatedAnnotations := map[string]string{} + for k, v := range helmette.SortedMap(dedicatedListenerAnnotations(&state.Values.Listeners, listenerName)) { + dedicatedAnnotations[k] = v + } + + svcType := dedicatedListenerServiceType(&state.Values.Listeners, listenerName) + sourceRanges := dedicatedListenerSourceRanges(&state.Values.Listeners, listenerName) + + svc := &corev1.Service{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "Service", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("lb-%s-%s", listenerName, podname), + Namespace: state.Release.Namespace, + Labels: labels, + Annotations: dedicatedAnnotations, + }, + Spec: corev1.ServiceSpec{ + ExternalTrafficPolicy: corev1.ServiceExternalTrafficPolicyLocal, + LoadBalancerSourceRanges: sourceRanges, + Ports: dedicatedPorts, + PublishNotReadyAddresses: true, + Selector: podSelector, + SessionAffinity: corev1.ServiceAffinityNone, + Type: svcType, + }, + } + + services = append(services, svc) + } } return services diff --git a/charts/redpanda/values.go b/charts/redpanda/values.go index 56346efc7..bb421912a 100644 --- a/charts/redpanda/values.go +++ b/charts/redpanda/values.go @@ -1674,6 +1674,56 @@ func (l *ListenerConfig[T]) ServicePorts(namePrefix string, external *ExternalCo return ports } +// ServicePortsForListener returns the ServicePort for a single named external +// listener, if it is enabled. +func (l *ListenerConfig[T]) ServicePortsForListener(namePrefix string, listenerName string, external *ExternalConfig) []corev1.ServicePort { + var ports []corev1.ServicePort + for name, listener := range helmette.SortedMap(l.External) { + if name != listenerName { + continue + } + if !ptr.Deref(listener.Enabled, external.Enabled) { + continue + } + + fallbackPorts := append(listener.AdvertisedPorts, l.Port) + + ports = append(ports, corev1.ServicePort{ + Name: fmt.Sprintf("%s-%s", namePrefix, name), + Protocol: corev1.ProtocolTCP, + AppProtocol: l.AppProtocol, + TargetPort: intstr.FromInt32(listener.Port), + Port: ptr.Deref(listener.NodePort, fallbackPorts[0]), + }) + } + return ports +} + +// ServicePortsExcludingListeners returns the ServicePorts for all enabled +// external listeners except those in the exclude set. +func (l *ListenerConfig[T]) ServicePortsExcludingListeners(namePrefix string, external *ExternalConfig, exclude map[string]bool) []corev1.ServicePort { + var ports []corev1.ServicePort + for name, listener := range helmette.SortedMap(l.External) { + if exclude[name] { + continue + } + if !ptr.Deref(listener.Enabled, external.Enabled) { + continue + } + + fallbackPorts := append(listener.AdvertisedPorts, l.Port) + + ports = append(ports, corev1.ServicePort{ + Name: fmt.Sprintf("%s-%s", namePrefix, name), + Protocol: corev1.ProtocolTCP, + AppProtocol: l.AppProtocol, + TargetPort: intstr.FromInt32(listener.Port), + Port: ptr.Deref(listener.NodePort, fallbackPorts[0]), + }) + } + return ports +} + // TrustStores returns a slice of all configured and enabled [TrustStore]s on // both internal and external listeners. func (l *ListenerConfig[T]) TrustStores(tls *TLS) []*TrustStore { @@ -1773,6 +1823,29 @@ type ExternalListener[T ~string] struct { AuthenticationMethod *T `json:"authenticationMethod,omitempty"` PrefixTemplate *string `json:"prefixTemplate,omitempty"` + + // Type, when set, causes this listener to be served by a dedicated + // per-broker Service of the specified type (e.g., LoadBalancer, NodePort) + // instead of sharing the default per-broker Service. This enables use + // cases like having a private listener on an internal LB and a public + // listener on an internet-facing LB. When not set, the listener shares + // the default per-broker Service created from the global external config. + Type *corev1.ServiceType `json:"type,omitempty" jsonschema:"pattern=^(LoadBalancer|NodePort)$"` + + // Annotations sets annotations on the dedicated Service for this listener. + // Only takes effect when Type is set. + Annotations map[string]string `json:"annotations,omitempty"` + + // LoadBalancerSourceRanges restricts traffic to the dedicated LoadBalancer + // for this listener to the specified CIDRs. Only takes effect when Type is + // set to LoadBalancer. + LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges,omitempty"` +} + +// HasDedicatedService returns true if this listener should get its own +// dedicated per-broker Service instead of sharing the default one. +func (l *ExternalListener[T]) HasDedicatedService() bool { + return l.Type != nil } func (l *ExternalListener[T]) AsString() ExternalListener[string] { @@ -1783,13 +1856,16 @@ func (l *ExternalListener[T]) AsString() ExternalListener[string] { } return ExternalListener[string]{ - Enabled: l.Enabled, - AdvertisedPorts: l.AdvertisedPorts, - Port: l.Port, - NodePort: l.NodePort, - TLS: l.TLS, - AuthenticationMethod: auth, - PrefixTemplate: l.PrefixTemplate, + Enabled: l.Enabled, + AdvertisedPorts: l.AdvertisedPorts, + Port: l.Port, + NodePort: l.NodePort, + TLS: l.TLS, + AuthenticationMethod: auth, + PrefixTemplate: l.PrefixTemplate, + Type: l.Type, + Annotations: l.Annotations, + LoadBalancerSourceRanges: l.LoadBalancerSourceRanges, } } diff --git a/charts/redpanda/values_partial.gen.go b/charts/redpanda/values_partial.gen.go index 626ad73c2..9bba685e1 100644 --- a/charts/redpanda/values_partial.gen.go +++ b/charts/redpanda/values_partial.gen.go @@ -404,13 +404,16 @@ type PartialSASLUser struct { } type PartialExternalListener[T ~string] struct { - Enabled *bool "json:\"enabled,omitempty\"" - AdvertisedPorts []int32 "json:\"advertisedPorts,omitempty\" jsonschema:\"minItems=1\"" - Port *int32 "json:\"port,omitempty\" jsonschema:\"required\"" - NodePort *int32 "json:\"nodePort,omitempty\"" - TLS *PartialExternalTLS "json:\"tls,omitempty\"" - AuthenticationMethod *T "json:\"authenticationMethod,omitempty\"" - PrefixTemplate *string "json:\"prefixTemplate,omitempty\"" + Enabled *bool "json:\"enabled,omitempty\"" + AdvertisedPorts []int32 "json:\"advertisedPorts,omitempty\" jsonschema:\"minItems=1\"" + Port *int32 "json:\"port,omitempty\" jsonschema:\"required\"" + NodePort *int32 "json:\"nodePort,omitempty\"" + TLS *PartialExternalTLS "json:\"tls,omitempty\"" + AuthenticationMethod *T "json:\"authenticationMethod,omitempty\"" + PrefixTemplate *string "json:\"prefixTemplate,omitempty\"" + Type *corev1.ServiceType "json:\"type,omitempty\" jsonschema:\"pattern=^(LoadBalancer|NodePort)$\"" + Annotations map[string]string "json:\"annotations,omitempty\"" + LoadBalancerSourceRanges []string "json:\"loadBalancerSourceRanges,omitempty\"" } type PartialTrustStore struct { diff --git a/operator/api/redpanda/v1alpha2/redpanda_clusterspec_types.go b/operator/api/redpanda/v1alpha2/redpanda_clusterspec_types.go index 150338b8a..74fc54f6b 100644 --- a/operator/api/redpanda/v1alpha2/redpanda_clusterspec_types.go +++ b/operator/api/redpanda/v1alpha2/redpanda_clusterspec_types.go @@ -973,6 +973,19 @@ type ExternalListener struct { // Specifies the network port that the external Service listens on. AdvertisedPorts []int32 `json:"advertisedPorts,omitempty"` NodePort *int32 `json:"nodePort,omitempty"` + + // Type, when set, causes this listener to be served by a dedicated + // per-broker Service of the specified type (e.g., LoadBalancer, NodePort) + // instead of sharing the default per-broker Service. + Type *corev1.ServiceType `json:"type,omitempty"` + + // Annotations sets annotations on the dedicated Service for this listener. + // Only takes effect when Type is set. + Annotations map[string]string `json:"annotations,omitempty"` + + // LoadBalancerSourceRanges restricts traffic to the dedicated LoadBalancer + // for this listener. Only takes effect when Type is set to LoadBalancer. + LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges,omitempty"` } // Admin configures settings for the Admin API listeners. diff --git a/operator/api/redpanda/v1alpha2/testdata/crd-docs.adoc b/operator/api/redpanda/v1alpha2/testdata/crd-docs.adoc index f88dad793..015d6d41d 100644 --- a/operator/api/redpanda/v1alpha2/testdata/crd-docs.adoc +++ b/operator/api/redpanda/v1alpha2/testdata/crd-docs.adoc @@ -1230,6 +1230,13 @@ internal and external listeners. However, it is ignored when specified + on internal listeners. + | | | *`advertisedPorts`* __integer array__ | Specifies the network port that the external Service listens on. + | | | *`nodePort`* __integer__ | | | +| *`type`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#servicetype-v1-core[$$ServiceType$$]__ | Type, when set, causes this listener to be served by a dedicated + +per-broker Service of the specified type (e.g., LoadBalancer, NodePort) + +instead of sharing the default per-broker Service. + | | +| *`annotations`* __object (keys:string, values:string)__ | Annotations sets annotations on the dedicated Service for this listener. + +Only takes effect when Type is set. + | | +| *`loadBalancerSourceRanges`* __string array__ | LoadBalancerSourceRanges restricts traffic to the dedicated LoadBalancer + +for this listener. Only takes effect when Type is set to LoadBalancer. + | | |=== diff --git a/operator/api/redpanda/v1alpha2/zz_generated.deepcopy.go b/operator/api/redpanda/v1alpha2/zz_generated.deepcopy.go index 20f88b122..32b577bf5 100644 --- a/operator/api/redpanda/v1alpha2/zz_generated.deepcopy.go +++ b/operator/api/redpanda/v1alpha2/zz_generated.deepcopy.go @@ -1566,6 +1566,23 @@ func (in *ExternalListener) DeepCopyInto(out *ExternalListener) { *out = new(int32) **out = **in } + if in.Type != nil { + in, out := &in.Type, &out.Type + *out = new(v1.ServiceType) + **out = **in + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.LoadBalancerSourceRanges != nil { + in, out := &in.LoadBalancerSourceRanges, &out.LoadBalancerSourceRanges + *out = make([]string, len(*in)) + copy(*out, *in) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExternalListener. diff --git a/operator/config/crd/bases/cluster.redpanda.com_redpandas.yaml b/operator/config/crd/bases/cluster.redpanda.com_redpandas.yaml index 21609c088..cd58855c8 100644 --- a/operator/config/crd/bases/cluster.redpanda.com_redpandas.yaml +++ b/operator/config/crd/bases/cluster.redpanda.com_redpandas.yaml @@ -1985,6 +1985,13 @@ spec: format: int32 type: integer type: array + annotations: + additionalProperties: + type: string + description: |- + Annotations sets annotations on the dedicated Service for this listener. + Only takes effect when Type is set. + type: object appProtocol: type: string authenticationMethod: @@ -1996,6 +2003,13 @@ spec: description: Specifies whether this Listener is enabled. type: boolean + loadBalancerSourceRanges: + description: |- + LoadBalancerSourceRanges restricts traffic to the dedicated LoadBalancer + for this listener. Only takes effect when Type is set to LoadBalancer. + items: + type: string + type: array nodePort: format: int32 type: integer @@ -2095,6 +2109,12 @@ spec: x-kubernetes-map-type: atomic type: object type: object + type: + description: |- + Type, when set, causes this listener to be served by a dedicated + per-broker Service of the specified type (e.g., LoadBalancer, NodePort) + instead of sharing the default per-broker Service. + type: string type: object description: Defines settings for the external listeners. type: object @@ -2218,6 +2238,13 @@ spec: format: int32 type: integer type: array + annotations: + additionalProperties: + type: string + description: |- + Annotations sets annotations on the dedicated Service for this listener. + Only takes effect when Type is set. + type: object appProtocol: type: string authenticationMethod: @@ -2229,6 +2256,13 @@ spec: description: Specifies whether this Listener is enabled. type: boolean + loadBalancerSourceRanges: + description: |- + LoadBalancerSourceRanges restricts traffic to the dedicated LoadBalancer + for this listener. Only takes effect when Type is set to LoadBalancer. + items: + type: string + type: array nodePort: format: int32 type: integer @@ -2328,6 +2362,12 @@ spec: x-kubernetes-map-type: atomic type: object type: object + type: + description: |- + Type, when set, causes this listener to be served by a dedicated + per-broker Service of the specified type (e.g., LoadBalancer, NodePort) + instead of sharing the default per-broker Service. + type: string type: object description: Defines settings for the external listeners. type: object @@ -2456,6 +2496,13 @@ spec: format: int32 type: integer type: array + annotations: + additionalProperties: + type: string + description: |- + Annotations sets annotations on the dedicated Service for this listener. + Only takes effect when Type is set. + type: object appProtocol: type: string authenticationMethod: @@ -2467,6 +2514,13 @@ spec: description: Specifies whether this Listener is enabled. type: boolean + loadBalancerSourceRanges: + description: |- + LoadBalancerSourceRanges restricts traffic to the dedicated LoadBalancer + for this listener. Only takes effect when Type is set to LoadBalancer. + items: + type: string + type: array nodePort: format: int32 type: integer @@ -2566,6 +2620,12 @@ spec: x-kubernetes-map-type: atomic type: object type: object + type: + description: |- + Type, when set, causes this listener to be served by a dedicated + per-broker Service of the specified type (e.g., LoadBalancer, NodePort) + instead of sharing the default per-broker Service. + type: string type: object description: Defines settings for the external listeners. type: object @@ -2777,6 +2837,13 @@ spec: format: int32 type: integer type: array + annotations: + additionalProperties: + type: string + description: |- + Annotations sets annotations on the dedicated Service for this listener. + Only takes effect when Type is set. + type: object appProtocol: type: string authenticationMethod: @@ -2788,6 +2855,13 @@ spec: description: Specifies whether this Listener is enabled. type: boolean + loadBalancerSourceRanges: + description: |- + LoadBalancerSourceRanges restricts traffic to the dedicated LoadBalancer + for this listener. Only takes effect when Type is set to LoadBalancer. + items: + type: string + type: array nodePort: format: int32 type: integer @@ -2887,6 +2961,12 @@ spec: x-kubernetes-map-type: atomic type: object type: object + type: + description: |- + Type, when set, causes this listener to be served by a dedicated + per-broker Service of the specified type (e.g., LoadBalancer, NodePort) + instead of sharing the default per-broker Service. + type: string type: object description: Defines settings for the external listeners. type: object @@ -35779,6 +35859,13 @@ spec: format: int32 type: integer type: array + annotations: + additionalProperties: + type: string + description: |- + Annotations sets annotations on the dedicated Service for this listener. + Only takes effect when Type is set. + type: object appProtocol: type: string authenticationMethod: @@ -35790,6 +35877,13 @@ spec: description: Specifies whether this Listener is enabled. type: boolean + loadBalancerSourceRanges: + description: |- + LoadBalancerSourceRanges restricts traffic to the dedicated LoadBalancer + for this listener. Only takes effect when Type is set to LoadBalancer. + items: + type: string + type: array nodePort: format: int32 type: integer @@ -35889,6 +35983,12 @@ spec: x-kubernetes-map-type: atomic type: object type: object + type: + description: |- + Type, when set, causes this listener to be served by a dedicated + per-broker Service of the specified type (e.g., LoadBalancer, NodePort) + instead of sharing the default per-broker Service. + type: string type: object description: Defines settings for the external listeners. type: object @@ -36012,6 +36112,13 @@ spec: format: int32 type: integer type: array + annotations: + additionalProperties: + type: string + description: |- + Annotations sets annotations on the dedicated Service for this listener. + Only takes effect when Type is set. + type: object appProtocol: type: string authenticationMethod: @@ -36023,6 +36130,13 @@ spec: description: Specifies whether this Listener is enabled. type: boolean + loadBalancerSourceRanges: + description: |- + LoadBalancerSourceRanges restricts traffic to the dedicated LoadBalancer + for this listener. Only takes effect when Type is set to LoadBalancer. + items: + type: string + type: array nodePort: format: int32 type: integer @@ -36122,6 +36236,12 @@ spec: x-kubernetes-map-type: atomic type: object type: object + type: + description: |- + Type, when set, causes this listener to be served by a dedicated + per-broker Service of the specified type (e.g., LoadBalancer, NodePort) + instead of sharing the default per-broker Service. + type: string type: object description: Defines settings for the external listeners. type: object @@ -36250,6 +36370,13 @@ spec: format: int32 type: integer type: array + annotations: + additionalProperties: + type: string + description: |- + Annotations sets annotations on the dedicated Service for this listener. + Only takes effect when Type is set. + type: object appProtocol: type: string authenticationMethod: @@ -36261,6 +36388,13 @@ spec: description: Specifies whether this Listener is enabled. type: boolean + loadBalancerSourceRanges: + description: |- + LoadBalancerSourceRanges restricts traffic to the dedicated LoadBalancer + for this listener. Only takes effect when Type is set to LoadBalancer. + items: + type: string + type: array nodePort: format: int32 type: integer @@ -36360,6 +36494,12 @@ spec: x-kubernetes-map-type: atomic type: object type: object + type: + description: |- + Type, when set, causes this listener to be served by a dedicated + per-broker Service of the specified type (e.g., LoadBalancer, NodePort) + instead of sharing the default per-broker Service. + type: string type: object description: Defines settings for the external listeners. type: object @@ -36571,6 +36711,13 @@ spec: format: int32 type: integer type: array + annotations: + additionalProperties: + type: string + description: |- + Annotations sets annotations on the dedicated Service for this listener. + Only takes effect when Type is set. + type: object appProtocol: type: string authenticationMethod: @@ -36582,6 +36729,13 @@ spec: description: Specifies whether this Listener is enabled. type: boolean + loadBalancerSourceRanges: + description: |- + LoadBalancerSourceRanges restricts traffic to the dedicated LoadBalancer + for this listener. Only takes effect when Type is set to LoadBalancer. + items: + type: string + type: array nodePort: format: int32 type: integer @@ -36681,6 +36835,12 @@ spec: x-kubernetes-map-type: atomic type: object type: object + type: + description: |- + Type, when set, causes this listener to be served by a dedicated + per-broker Service of the specified type (e.g., LoadBalancer, NodePort) + instead of sharing the default per-broker Service. + type: string type: object description: Defines settings for the external listeners. type: object