This is an automated email from the ASF dual-hosted git repository.

adutra pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/polaris.git


The following commit(s) were added to refs/heads/main by this push:
     new 9fc2e0d7f Helm chart: fix logic for deduplicating ports (#3790)
9fc2e0d7f is described below

commit 9fc2e0d7f2c6ca381faef3599f866a4a58754295
Author: Alexandre Dutra <[email protected]>
AuthorDate: Tue Feb 17 19:39:31 2026 +0100

    Helm chart: fix logic for deduplicating ports (#3790)
    
    The logic in `polaris.containerPorts` has been improved to prevent 
duplicate ports in a `Deployment`.
    
    Summary of changes:
    
    - Container ports are keyed by port number instead of name to prevent
      duplicate `containerPort` entries (invalid in Kubernetes)
    - Validate that both port numbers and port names are unique
    - Extract validation logic into `polaris.validateContainerPort` helper 
template
    - Fix documentation of `targetPort`: this field must be a number
    - Update tests to reflect new validation behavior
    - Fixed `extra-service-values.yaml` fixture (had invalid port declarations)
---
 helm/polaris/ci/extra-service-values.yaml |   4 +-
 helm/polaris/templates/_helpers.tpl       |  72 ++++++-----
 helm/polaris/tests/deployment_test.yaml   | 208 ++++++++++++++++++++++++------
 helm/polaris/values.yaml                  |   6 +-
 site/content/in-dev/unreleased/helm.md    |   4 +-
 5 files changed, 219 insertions(+), 75 deletions(-)

diff --git a/helm/polaris/ci/extra-service-values.yaml 
b/helm/polaris/ci/extra-service-values.yaml
index e19835a83..eadd13c61 100644
--- a/helm/polaris/ci/extra-service-values.yaml
+++ b/helm/polaris/ci/extra-service-values.yaml
@@ -32,7 +32,7 @@ service:
       protocol: TCP
     - name: polaris-http2
       port: 28181
-      targetPort: 8181
+      targetPort: 8183
       protocol: TCP
 
 extraServices:
@@ -44,4 +44,4 @@ extraServices:
     ports:
     - name: polaris-http2
       port: 38181
-      targetPort: 8181
+      targetPort: 8183
diff --git a/helm/polaris/templates/_helpers.tpl 
b/helm/polaris/templates/_helpers.tpl
index 584158210..bd226abf3 100644
--- a/helm/polaris/templates/_helpers.tpl
+++ b/helm/polaris/templates/_helpers.tpl
@@ -267,53 +267,63 @@ 
https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/
 {{- end -}}
 
 {{/*
-Prints the ports section of the container spec. Also validates all port names 
to ensure
-that they are unique.
+Helper template to validate and register a container port.
+Arguments (passed as a list):
+  0: $ports dict (mutated) - maps port number to {name, protocol}
+  1: $names dict (mutated) - maps port name to port number
+  2: $errorPrefix string - prefix for error messages (e.g. "service.ports[0]")
+  3: $port object - the port definition from the values.yaml with name, port, 
targetPort, protocol
+*/}}
+{{- define "polaris.validateContainerPort" -}}
+{{- $ports := index . 0 -}}
+{{- $names := index . 1 -}}
+{{- $errorPrefix := index . 2 -}}
+{{- $port := index . 3 -}}
+{{- $portNumber := coalesce $port.targetPort $port.port | toString -}}
+{{- $protocol := $port.protocol | default "TCP" -}}
+{{- if hasKey $ports $portNumber -}}
+{{- $existing := get $ports $portNumber -}}
+{{- if ne $port.name (index $existing "name") -}}
+{{- fail (printf "%s: port number %s has conflicting name, expected %v, got 
%v" $errorPrefix $portNumber (index $existing "name") $port.name) -}}
+{{- end -}}
+{{- if ne $protocol (index $existing "protocol") -}}
+{{- fail (printf "%s: port number %s has conflicting protocol, expected %v, 
got %v" $errorPrefix $portNumber (index $existing "protocol") $protocol) -}}
+{{- end -}}
+{{- else if hasKey $names $port.name -}}
+{{- fail (printf "%s: port name %s has conflicting number, expected %v, got 
%v" $errorPrefix $port.name (get $names $port.name) $portNumber) -}}
+{{- else -}}
+{{- $_ := set $ports $portNumber (dict "name" $port.name "protocol" $protocol) 
-}}
+{{- $_ = set $names $port.name $portNumber -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Prints the ports section of the container spec. Iterates over all service port 
declarations
+and determines which ports the container should expose, ensuring no duplicate 
port numbers
+or port names.
 */}}
 {{- define "polaris.containerPorts" -}}
 {{- $ports := dict -}}
-{{- $protocols := dict -}}
+{{- $names := dict -}}
 {{- /* Main service ports */ -}}
 {{- range $i, $port := .Values.service.ports -}}
-{{- if hasKey $ports $port.name -}}
-{{- fail (printf "service.ports[%d]: port name already taken: %v" $i 
$port.name) -}}
-{{- end -}}
-{{- $portNumber := coalesce $port.targetPort $port.port -}}
-{{- $_ := set $ports $port.name $portNumber -}}
-{{- $_ = set $protocols $port.name ($port.protocol | default "TCP") -}}
+{{- include "polaris.validateContainerPort" (list $ports $names (printf 
"service.ports[%d]" $i) $port) -}}
 {{- end -}}
 {{- /* Management service ports */ -}}
 {{- range $i, $port := .Values.managementService.ports -}}
-{{- if hasKey $ports $port.name -}}
-{{- fail (printf "managementService.ports[%d]: port name already taken: %v" $i 
$port.name) -}}
-{{- end -}}
-{{- $portNumber := coalesce $port.targetPort $port.port -}}
-{{- $_ := set $ports $port.name $portNumber }}
-{{- $_ = set $protocols $port.name ($port.protocol | default "TCP") -}}
+{{- include "polaris.validateContainerPort" (list $ports $names (printf 
"managementService.ports[%d]" $i) $port) -}}
 {{- end -}}
 {{- /* Extra service ports */ -}}
 {{- range $i, $svc := .Values.extraServices -}}
 {{- range $j, $port := $svc.ports -}}
-{{- $portNumber := coalesce $port.targetPort $port.port -}}
-{{- if hasKey $ports $port.name -}}
-{{- if ne $portNumber (get $ports $port.name) -}}
-{{- fail (printf "extraServices[%d].ports[%d]: wrong port number for port %s, 
expected %v, got %v" $i $j $port.name (get $ports $port.name) $portNumber) -}}
-{{- end -}}
-{{- end -}}
-{{- if hasKey $protocols $port.name -}}
-{{- if ne ($port.protocol | default "TCP") (get $protocols $port.name) -}}
-{{- fail (printf "extraServices[%d].ports[%d]: wrong protocol for port %s, 
expected %v, got %v" $i $j $port.name (get $protocols $port.name) 
$port.protocol) -}}
-{{- end -}}
-{{- end -}}
-{{- $_ := set $ports $port.name $portNumber -}}
-{{- $_ = set $protocols $port.name ($port.protocol | default "TCP") -}}
+{{- include "polaris.validateContainerPort" (list $ports $names (printf 
"extraServices[%d].ports[%d]" $i $j) $port) -}}
 {{- end -}}
 {{- end }}
 ports:
-{{- range $portName, $portNumber := $ports }}
-  - name: {{ $portName }}
+{{- range $portNumber, $portInfo := $ports }}
+  - name: {{ index $portInfo "name" }}
     containerPort: {{ $portNumber }}
-    protocol: {{ get $protocols $portName }}
+    protocol: {{ index $portInfo "protocol" }}
 {{- end }}
 {{- end -}}
 
diff --git a/helm/polaris/tests/deployment_test.yaml 
b/helm/polaris/tests/deployment_test.yaml
index 71c84ac86..d0c1d7f41 100644
--- a/helm/polaris/tests/deployment_test.yaml
+++ b/helm/polaris/tests/deployment_test.yaml
@@ -514,7 +514,7 @@ tests:
             containerPort: 8183
             protocol: TCP
 
-  - it: should fail if port name is not unique (#1)
+  - it: should fail when duplicate port names have different port numbers in 
service
     template: deployment.yaml
     set:
       service:
@@ -525,9 +525,9 @@ tests:
             port: 18181
     asserts:
       - failedTemplate:
-          errorPattern: "service.ports\\[\\d\\]: port name already taken: 
polaris-http"
+          errorMessage: "service.ports[1]: port name polaris-http has 
conflicting number, expected 8181, got 18181"
 
-  - it: should fail if port name is not unique (#2)
+  - it: should fail when duplicate port names have different port numbers in 
managementService
     template: deployment.yaml
     set:
       managementService:
@@ -538,9 +538,39 @@ tests:
             port: 18182
     asserts:
       - failedTemplate:
-          errorPattern: "managementService.ports\\[\\d\\]: port name already 
taken: polaris-mgmt"
+          errorMessage: "managementService.ports[1]: port name polaris-mgmt 
has conflicting number, expected 8182, got 18182"
 
-  - it: should fail if port name is not unique (#3)
+  - it: should fail when duplicate port names have different port numbers in 
extraServices (#1)
+    template: deployment.yaml
+    set:
+      extraServices:
+        - nameSuffix: ext
+          ports:
+            - name: polaris-extra
+              port: 8183
+            - name: polaris-extra
+              port: 18183
+    asserts:
+      - failedTemplate:
+          errorMessage: "extraServices[0].ports[1]: port name polaris-extra 
has conflicting number, expected 8183, got 18183"
+
+  - it: should fail when duplicate port names have different port numbers in 
extraServices (#2)
+    template: deployment.yaml
+    set:
+      extraServices:
+        - nameSuffix: ext1
+          ports:
+            - name: polaris-extra
+              port: 8183
+        - nameSuffix: ext
+          ports:
+            - name: polaris-extra
+              port: 18183
+    asserts:
+      - failedTemplate:
+          errorMessage: "extraServices[1].ports[0]: port name polaris-extra 
has conflicting number, expected 8183, got 18183"
+
+  - it: should fail when duplicate port names have different port numbers 
across services (#1)
     template: deployment.yaml
     set:
       service:
@@ -553,9 +583,25 @@ tests:
             port: 8182
     asserts:
       - failedTemplate:
-          errorPattern: "managementService.ports\\[\\d\\]: port name already 
taken: polaris"
+          errorMessage: "managementService.ports[0]: port name polaris has 
conflicting number, expected 8181, got 8182"
+
+  - it: should fail when duplicate port names have different port numbers 
across services (#2)
+    template: deployment.yaml
+    set:
+      service:
+        ports:
+          - name: polaris
+            port: 8181
+      extraServices:
+        - nameSuffix: ext
+          ports:
+            - name: polaris
+              port: 8182
+    asserts:
+      - failedTemplate:
+          errorMessage: "extraServices[0].ports[0]: port number 8182 has 
conflicting name, expected polaris-mgmt, got polaris"
 
-  - it: should not fail when extra service references the same port name and 
number
+  - it: should deduplicate when extra service references the same port number 
and name
     template: deployment.yaml
     set:
       extraServices:
@@ -581,6 +627,26 @@ tests:
             containerPort: 8182
             protocol: TCP
 
+  - it: should add extra service port with different number and name
+    template: deployment.yaml
+    set:
+      extraServices:
+        - nameSuffix: "-extra"
+          type: LoadBalancer
+          ports:
+            - name: polaris-extra
+              port: 9999
+    asserts:
+      - lengthEqual:
+          path: spec.template.spec.containers[0].ports
+          count: 3
+      - contains:
+          path: spec.template.spec.containers[0].ports
+          content:
+            name: polaris-extra
+            containerPort: 9999
+            protocol: TCP
+
   - it: should fail when extra service references the same port name with 
different number (#1)
     template: deployment.yaml
     set:
@@ -591,8 +657,8 @@ tests:
             - name: polaris-http
               port: 9999
     asserts:
-        - failedTemplate:
-            errorPattern: "extraServices\\[\\d\\].ports\\[\\d\\]: wrong port 
number for port polaris-http, expected 8181, got 9999"
+      - failedTemplate:
+          errorMessage: "extraServices[0].ports[0]: port name polaris-http has 
conflicting number, expected 8181, got 9999"
 
   - it: should fail when extra service references the same port name with 
different number (#2)
     template: deployment.yaml
@@ -603,30 +669,112 @@ tests:
           ports:
             - name: polaris-mgmt
               port: 9999
+    asserts:
+      - failedTemplate:
+          errorMessage: "extraServices[0].ports[0]: port name polaris-mgmt has 
conflicting number, expected 8182, got 9999"
+
+  - it: should fail when same port number has conflicting name in service
+    template: deployment.yaml
+    set:
+      service:
+        ports:
+          - name: polaris-http
+            port: 8181
+          - name: polaris-http2
+            port: 8181
     asserts:
         - failedTemplate:
-            errorPattern: "extraServices\\[\\d\\].ports\\[\\d\\]: wrong port 
number for port polaris-mgmt, expected 8182, got 9999"
+            errorMessage: "service.ports[1]: port number 8181 has conflicting 
name, expected polaris-http, got polaris-http2"
 
-  - it: should fail when extra service references the same port name with 
different number (#3)
+  - it: should fail when same port number has conflicting name in 
managementService
+    template: deployment.yaml
+    set:
+      managementService:
+        ports:
+          - name: polaris-mgmt
+            port: 8182
+          - name: polaris-mgmt2
+            port: 8182
+    asserts:
+        - failedTemplate:
+            errorMessage: "managementService.ports[1]: port number 8182 has 
conflicting name, expected polaris-mgmt, got polaris-mgmt2"
+
+  - it: should fail when same port number has conflicting name in 
extraServices (#1)
+    template: deployment.yaml
+    set:
+      extraServices:
+        - nameSuffix: ext
+          ports:
+            - name: polaris-extra
+              port: 8183
+            - name: polaris-extra2
+              port: 8183
+    asserts:
+        - failedTemplate:
+            errorMessage: "extraServices[0].ports[1]: port number 8183 has 
conflicting name, expected polaris-extra, got polaris-extra2"
+
+  - it: should fail when same port number has conflicting name in 
extraServices (#2)
+    template: deployment.yaml
+    set:
+      extraServices:
+        - nameSuffix: ext1
+          ports:
+            - name: polaris-extra
+              port: 8183
+        - nameSuffix: ext2
+          ports:
+            - name: polaris-extra2
+              port: 8183
+    asserts:
+        - failedTemplate:
+            errorMessage: "extraServices[1].ports[0]: port number 8183 has 
conflicting name, expected polaris-extra, got polaris-extra2"
+
+  - it: should fail when extra service has conflicting name for same port 
number
     template: deployment.yaml
     set:
       service:
         ports:
           - name: polaris-http
             port: 8181
-          - name: polaris-https
-            port: 8043
       extraServices:
         - nameSuffix: "-extra"
           type: LoadBalancer
           ports:
-            - name: polaris-https
-              port: 9999
+            - name: polaris-extra
+              port: 8181
+    asserts:
+        - failedTemplate:
+            errorMessage: "extraServices[0].ports[0]: port number 8181 has 
conflicting name, expected polaris-http, got polaris-extra"
+
+  - it: should fail when same port number has conflicting protocol in service
+    template: deployment.yaml
+    set:
+      service:
+        ports:
+          - name: polaris-http
+            port: 8181
+          - name: polaris-http
+            port: 8181
+            protocol: UDP
+    asserts:
+        - failedTemplate:
+            errorMessage: "service.ports[1]: port number 8181 has conflicting 
protocol, expected TCP, got UDP"
+
+  - it: should fail when same port number has conflicting protocol in 
managementService
+    template: deployment.yaml
+    set:
+      managementService:
+        ports:
+          - name: polaris-mgmt
+            port: 8182
+          - name: polaris-mgmt
+            port: 8182
+            protocol: UDP
     asserts:
         - failedTemplate:
-            errorPattern: "extraServices\\[\\d\\].ports\\[\\d\\]: wrong port 
number for port polaris-https, expected 8043, got 9999"
+            errorMessage: "managementService.ports[1]: port number 8182 has 
conflicting protocol, expected TCP, got UDP"
 
-  - it: should fail when extra service references the same port name with 
different protocol
+  - it: should fail when same port number has conflicting protocol in 
extraServices
     template: deployment.yaml
     set:
       service:
@@ -642,34 +790,28 @@ tests:
               protocol: UDP
     asserts:
         - failedTemplate:
-            errorPattern: "extraServices\\[\\d\\].ports\\[\\d\\]: wrong 
protocol for port polaris-http, expected TCP, got UDP"
+            errorMessage: "extraServices[0].ports[0]: port number 8181 has 
conflicting protocol, expected TCP, got UDP"
 
-  - it: should create 2 ports with same number
+  - it: should deduplicate ports with same number and name
     template: deployment.yaml
     set:
       service:
         ports:
           - name: polaris-http
             port: 8181
-          - name: polaris-http2
+          - name: polaris-http
             port: 8181
     asserts:
       - lengthEqual:
           path: spec.template.spec.containers[0].ports
-          count: 3
+          count: 2
       - contains:
           path: spec.template.spec.containers[0].ports
           content:
             name: polaris-http
             containerPort: 8181
             protocol: TCP
-      - contains:
-          path: spec.template.spec.containers[0].ports
-          content:
-            name: polaris-http2
-            containerPort: 8181
-            protocol: TCP
-  - it: should create 2 ports with same number using targetPort
+  - it: should deduplicate ports with same number and name using targetPort
     template: deployment.yaml
     set:
       service:
@@ -677,25 +819,19 @@ tests:
           - name: polaris-http
             port: 18181
             targetPort: 8181
-          - name: polaris-http2
+          - name: polaris-http
             port: 18181
             targetPort: 8181
     asserts:
       - lengthEqual:
           path: spec.template.spec.containers[0].ports
-          count: 3
+          count: 2
       - contains:
           path: spec.template.spec.containers[0].ports
           content:
             name: polaris-http
             containerPort: 8181
             protocol: TCP
-      - contains:
-          path: spec.template.spec.containers[0].ports
-          content:
-            name: polaris-http2
-            containerPort: 8181
-            protocol: TCP
   - it: should set port protocols
     template: deployment.yaml
     set:
diff --git a/helm/polaris/values.yaml b/helm/polaris/values.yaml
index 281d77cec..d110dff5e 100644
--- a/helm/polaris/values.yaml
+++ b/helm/polaris/values.yaml
@@ -110,8 +110,7 @@ service:
     - name: polaris-http
       # -- The port the service listens on. By default, the HTTP port is 8181.
       port: 8181
-      # -- Number or name of the port to access on the pods targeted by the 
service.
-      # If this is a string, it will be looked up as a named port in the 
target Pod's container ports.
+      # -- Number of the port to access on the pods targeted by the service.
       # If this is not specified, the value of the 'port' field is used.
       targetPort: ~  # polaris-service
       # -- The port on each node on which this service is exposed when type is 
NodePort or LoadBalancer.
@@ -171,8 +170,7 @@ managementService:
       # -- The port the management service listens on. By default, the 
management interface is exposed
       # on HTTP port 8182.
       port: 8182
-      # -- Number or name of the port to access on the pods targeted by the 
service.
-      # If this is a string, it will be looked up as a named port in the 
target Pod's container ports.
+      # -- Number of the port to access on the pods targeted by the service.
       # If this is not specified, the value of the 'port' field is used.
       targetPort: ~  # polaris-service
       # -- The port on each node on which this service is exposed when type is 
NodePort or LoadBalancer.
diff --git a/site/content/in-dev/unreleased/helm.md 
b/site/content/in-dev/unreleased/helm.md
index 14215a88a..c5b4c75c4 100644
--- a/site/content/in-dev/unreleased/helm.md
+++ b/site/content/in-dev/unreleased/helm.md
@@ -361,7 +361,7 @@ ct install --namespace polaris --charts ./helm/polaris
 | managementService.ports[0].nodePort | string | `nil` | The port on each node 
on which this service is exposed when type is NodePort or LoadBalancer. Usually 
assigned by the system. If not specified, a port will be allocated if this 
Service requires one. If this field is specified when creating a Service which 
does not need it, creation will fail. |
 | managementService.ports[0].port | int | `8182` | The port the management 
service listens on. By default, the management interface is exposed on HTTP 
port 8182. |
 | managementService.ports[0].protocol | string | `nil` | The IP protocol for 
this port. Supports "TCP", "UDP", and "SCTP". Default is TCP. |
-| managementService.ports[0].targetPort | string | `nil` | Number or name of 
the port to access on the pods targeted by the service. If this is a string, it 
will be looked up as a named port in the target Pod's container ports. If this 
is not specified, the value of the 'port' field is used. |
+| managementService.ports[0].targetPort | string | `nil` | Number of the port 
to access on the pods targeted by the service. If this is not specified, the 
value of the 'port' field is used. |
 | managementService.type | string | `"ClusterIP"` | The type of service to 
create. Valid values are: ExternalName, ClusterIP, NodePort, and LoadBalancer. 
The default value is ClusterIP. |
 | metrics.enabled | bool | `true` | Specifies whether metrics for the polaris 
server should be enabled. |
 | metrics.tags | object | `{}` | Additional tags (dimensional labels) to add 
to the metrics. |
@@ -431,7 +431,7 @@ ct install --namespace polaris --charts ./helm/polaris
 | service.ports[0].nodePort | string | `nil` | The port on each node on which 
this service is exposed when type is NodePort or LoadBalancer. Usually assigned 
by the system. If not specified, a port will be allocated if this Service 
requires one. If this field is specified when creating a Service which does not 
need it, creation will fail. |
 | service.ports[0].port | int | `8181` | The port the service listens on. By 
default, the HTTP port is 8181. |
 | service.ports[0].protocol | string | `nil` | The IP protocol for this port. 
Supports "TCP", "UDP", and "SCTP". Default is TCP. |
-| service.ports[0].targetPort | string | `nil` | Number or name of the port to 
access on the pods targeted by the service. If this is a string, it will be 
looked up as a named port in the target Pod's container ports. If this is not 
specified, the value of the 'port' field is used. |
+| service.ports[0].targetPort | string | `nil` | Number of the port to access 
on the pods targeted by the service. If this is not specified, the value of the 
'port' field is used. |
 | service.sessionAffinity | string | `nil` | The session affinity for the 
service. Valid values are: None, ClientIP. The default value is None. ClientIP 
enables sticky sessions based on the client's IP address. This is generally 
beneficial to Polaris deployments, but some testing may be required in order to 
make sure that the load is distributed evenly among the pods. Also, this 
setting affects only internal clients, not external ones. If Ingress is 
enabled, it is recommended to set sess [...]
 | service.trafficDistribution | string | `nil` | The traffic distribution 
field provides another way to influence traffic routing within a Kubernetes 
Service. While traffic policies focus on strict semantic guarantees, traffic 
distribution allows you to express preferences such as routing to topologically 
closer endpoints. The only valid value is: PreferClose. The default value is 
implementation-specific. |
 | service.type | string | `"ClusterIP"` | The type of service to create. Valid 
values are: ExternalName, ClusterIP, NodePort, and LoadBalancer. The default 
value is ClusterIP. |

Reply via email to