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

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


The following commit(s) were added to refs/heads/main by this push:
     new 0e96563519 [#10866] feat(charts): Support Gateway API HTTPRoute in 
Helm charts (#11308)
0e96563519 is described below

commit 0e96563519b98fbef903e833f8dafb314afa0b23
Author: somaz <[email protected]>
AuthorDate: Thu Jul 2 16:18:57 2026 +0900

    [#10866] feat(charts): Support Gateway API HTTPRoute in Helm charts (#11308)
    
    ### What changes were proposed in this pull request?
    
    Add an opt-in `ingress.type` field to the Gravitino, Iceberg REST, and
    Lance REST
    Helm charts. It defaults to `ingress` (renders the existing
    `networking.k8s.io/v1`
    Ingress, fully backward compatible). When set to `gateway`, the chart
    renders a
    Kubernetes Gateway API `HTTPRoute` (`gateway.networking.k8s.io/v1`)
    instead of an
    Ingress.
    
    - New template `templates/httproute.yaml` in all three charts.
    - Existing `templates/ingress.yaml` is now gated to skip when `type:
    gateway`, so
      the two resources are mutually exclusive.
    - New `ingress.gateway` block (`apiVersion`, `parentRefs`) in
    `values.yaml`. The
    existing `hosts` / `paths` / `annotations` are reused for the HTTPRoute.
    - helm-unittest coverage added for the Iceberg chart
    (`httproute_test.yaml`, plus a
      case asserting the Ingress is not rendered in gateway mode).
    
    Note: `tls` and `className` are Ingress-only and are intentionally not
    consumed by
    HTTPRoute — Gateway API terminates TLS at the parent Gateway listener.
    
    ### Why are the changes needed?
    
    The charts currently only support the legacy Ingress resource. The
    Gateway API is
    the successor to Ingress and the standard in modern Kubernetes
    environments. This
    lets users on a Gateway API stack expose Gravitino services without
    bolting an
    Ingress controller alongside their Gateway.
    
    Fix: #10866
    
    ### Does this PR introduce _any_ user-facing change?
    
    Yes — a new opt-in chart value `ingress.type` (default `ingress`) and an
    `ingress.gateway` block. Existing installations are unaffected because
    the default
    preserves the current Ingress behavior.
    
    ### How was this patch tested?
    
    - `helm unittest --with-subchart=false
    dev/charts/gravitino-iceberg-rest-server`
      → 8 suites, 27 tests pass (includes the new httproute suite).
    - `helm template` on all three charts: `type: gateway` renders an
    HTTPRoute and no
      Ingress; default/`type: ingress` renders an Ingress and no HTTPRoute.
    - `helm lint` passes for the iceberg and lance charts.
    
    ---
    
    ##### Was generative AI tooling used to co-author this PR?
    
    - [X] Yes — Claude Code (Opus 4.8)
    
    Generated-by: Claude Code (Opus 4.8)
---
 .../templates/httproute.yaml                       |  67 +++++++
 .../templates/ingress.yaml                         |   2 +-
 .../tests/httproute_test.yaml                      | 205 +++++++++++++++++++++
 .../tests/ingress_test.yaml                        |   9 +
 .../gravitino-iceberg-rest-server/values.yaml      |  19 ++
 .../templates/httproute.yaml                       |  67 +++++++
 .../templates/ingress.yaml                         |   2 +-
 .../tests/httproute_test.yaml                      | 154 ++++++++++++++++
 .../tests/ingress_test.yaml                        |   9 +
 dev/charts/gravitino-lance-rest-server/values.yaml |  19 ++
 dev/charts/gravitino/templates/httproute.yaml      |  67 +++++++
 dev/charts/gravitino/templates/ingress.yaml        |   4 +-
 dev/charts/gravitino/tests/httproute_test.yaml     | 154 ++++++++++++++++
 dev/charts/gravitino/tests/ingress_test.yaml       |   9 +
 dev/charts/gravitino/values.yaml                   |  19 ++
 15 files changed, 802 insertions(+), 4 deletions(-)

diff --git a/dev/charts/gravitino-iceberg-rest-server/templates/httproute.yaml 
b/dev/charts/gravitino-iceberg-rest-server/templates/httproute.yaml
new file mode 100644
index 0000000000..0186127c7f
--- /dev/null
+++ b/dev/charts/gravitino-iceberg-rest-server/templates/httproute.yaml
@@ -0,0 +1,67 @@
+{{- /*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  */}}
+
+{{- if and .Values.ingress.enabled (eq (.Values.ingress.type | default 
"ingress") "gateway") -}}
+{{- $fullName := include "gravitino-iceberg-rest-server.fullname" . -}}
+{{- $svcPort := .Values.service.port -}}
+{{- $gateway := .Values.ingress.gateway | default dict -}}
+{{- $root := . -}}
+{{- /* Render one HTTPRoute per host so that, like the Ingress, each host only
+   matches its own paths (HTTPRoute hostnames apply to the whole resource). 
*/}}
+{{- range $hostIndex, $hostEntry := .Values.ingress.hosts }}
+{{- if $hostIndex }}
+---
+{{- end }}
+apiVersion: {{ $gateway.apiVersion | default "gateway.networking.k8s.io/v1" }}
+kind: HTTPRoute
+metadata:
+  name: {{ $fullName }}{{ if $hostIndex }}-{{ $hostIndex }}{{ end }}
+  labels:
+    {{- include "gravitino-iceberg-rest-server.labels" $root | nindent 4 }}
+  {{- with $root.Values.ingress.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+spec:
+  {{- with $gateway.parentRefs }}
+  parentRefs:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+  {{- if $hostEntry.host }}
+  hostnames:
+    - {{ $hostEntry.host | quote }}
+  {{- end }}
+  rules:
+    {{- range $hostEntry.paths }}
+    {{- $pathType := .pathType | default "Prefix" }}
+    {{- if or (eq $pathType "Prefix") (eq $pathType "PathPrefix") (eq 
$pathType "ImplementationSpecific") }}
+    {{- $pathType = "PathPrefix" }}
+    {{- else if ne $pathType "Exact" }}
+    {{- fail (printf "ingress.hosts[].paths[].pathType %q is not supported 
when ingress.type is \"gateway\"; use Exact, Prefix, or ImplementationSpecific" 
$pathType) }}
+    {{- end }}
+    - matches:
+        - path:
+            type: {{ $pathType }}
+            value: {{ .path | quote }}
+      backendRefs:
+        - name: {{ $fullName }}
+          port: {{ $svcPort }}
+    {{- end }}
+{{- end }}
+{{- end }}
diff --git a/dev/charts/gravitino-iceberg-rest-server/templates/ingress.yaml 
b/dev/charts/gravitino-iceberg-rest-server/templates/ingress.yaml
index 67cd365fba..337ca2809e 100644
--- a/dev/charts/gravitino-iceberg-rest-server/templates/ingress.yaml
+++ b/dev/charts/gravitino-iceberg-rest-server/templates/ingress.yaml
@@ -17,7 +17,7 @@
   under the License.
   */}}
 
-{{- if .Values.ingress.enabled -}}
+{{- if and .Values.ingress.enabled (ne (.Values.ingress.type | default 
"ingress") "gateway") -}}
 {{- $fullName := include "gravitino-iceberg-rest-server.fullname" . -}}
 {{- $svcPort := .Values.service.port -}}
 {{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" 
.Capabilities.KubeVersion.GitVersion)) }}
diff --git a/dev/charts/gravitino-iceberg-rest-server/tests/httproute_test.yaml 
b/dev/charts/gravitino-iceberg-rest-server/tests/httproute_test.yaml
new file mode 100644
index 0000000000..ea370bbde2
--- /dev/null
+++ b/dev/charts/gravitino-iceberg-rest-server/tests/httproute_test.yaml
@@ -0,0 +1,205 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+suite: test gravitino iceberg rest server httproute
+templates:
+  - httproute.yaml
+tests:
+  - it: does not render httproute by default
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: does not render httproute when type is the default ingress
+    set:
+      ingress:
+        enabled: true
+        type: ingress
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: renders a Gateway API HTTPRoute when type is gateway
+    release:
+      name: iceberg-rest
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        annotations:
+          example.com/route: "true"
+        hosts:
+          - host: iceberg-rest.example.com
+            paths:
+              - path: /iceberg
+                pathType: Prefix
+              - path: /exact
+                pathType: Exact
+        gateway:
+          parentRefs:
+            - name: external
+              namespace: gateway-system
+              sectionName: https
+    asserts:
+      - isAPIVersion:
+          of: gateway.networking.k8s.io/v1
+      - isKind:
+          of: HTTPRoute
+      - equal:
+          path: metadata.name
+          value: iceberg-rest-gravitino-iceberg-rest-server-helm
+      - equal:
+          path: metadata.annotations["example.com/route"]
+          value: "true"
+      - equal:
+          path: spec.parentRefs[0].name
+          value: external
+      - equal:
+          path: spec.parentRefs[0].namespace
+          value: gateway-system
+      - equal:
+          path: spec.parentRefs[0].sectionName
+          value: https
+      - contains:
+          path: spec.hostnames
+          content: iceberg-rest.example.com
+      - equal:
+          path: spec.rules[0].matches[0].path.type
+          value: PathPrefix
+      - equal:
+          path: spec.rules[0].matches[0].path.value
+          value: /iceberg
+      - equal:
+          path: spec.rules[1].matches[0].path.type
+          value: Exact
+      - equal:
+          path: spec.rules[1].matches[0].path.value
+          value: /exact
+      - equal:
+          path: spec.rules[0].backendRefs[0].name
+          value: iceberg-rest-gravitino-iceberg-rest-server-helm
+      - equal:
+          path: spec.rules[0].backendRefs[0].port
+          value: 9001
+
+  - it: maps ImplementationSpecific pathType to PathPrefix in gateway mode
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        hosts:
+          - host: iceberg-rest.example.com
+            paths:
+              - path: /
+                pathType: ImplementationSpecific
+        gateway:
+          parentRefs:
+            - name: external
+    asserts:
+      - equal:
+          path: spec.rules[0].matches[0].path.type
+          value: PathPrefix
+      - equal:
+          path: spec.rules[0].matches[0].path.value
+          value: /
+
+  - it: defaults pathType to PathPrefix when unset in gateway mode
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        hosts:
+          - host: iceberg-rest.example.com
+            paths:
+              - path: /api
+        gateway:
+          parentRefs:
+            - name: external
+    asserts:
+      - equal:
+          path: spec.rules[0].matches[0].path.type
+          value: PathPrefix
+
+  - it: fails rendering on an unsupported pathType in gateway mode
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        hosts:
+          - host: iceberg-rest.example.com
+            paths:
+              - path: /re
+                pathType: RegularExpression
+        gateway:
+          parentRefs:
+            - name: external
+    asserts:
+      - failedTemplate:
+          errorMessage: 'ingress.hosts[].paths[].pathType "RegularExpression" 
is not supported when ingress.type is "gateway"; use Exact, Prefix, or 
ImplementationSpecific'
+
+  - it: renders one HTTPRoute per host so paths stay scoped to their host
+    release:
+      name: iceberg-rest
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        hosts:
+          - host: a.example.com
+            paths:
+              - path: /a
+                pathType: Prefix
+          - host: b.example.com
+            paths:
+              - path: /b
+                pathType: Prefix
+        gateway:
+          parentRefs:
+            - name: external
+    asserts:
+      - hasDocuments:
+          count: 2
+      - equal:
+          path: metadata.name
+          value: iceberg-rest-gravitino-iceberg-rest-server-helm
+        documentIndex: 0
+      - contains:
+          path: spec.hostnames
+          content: a.example.com
+        documentIndex: 0
+      - notContains:
+          path: spec.hostnames
+          content: b.example.com
+        documentIndex: 0
+      - equal:
+          path: spec.rules[0].matches[0].path.value
+          value: /a
+        documentIndex: 0
+      - equal:
+          path: metadata.name
+          value: iceberg-rest-gravitino-iceberg-rest-server-helm-1
+        documentIndex: 1
+      - contains:
+          path: spec.hostnames
+          content: b.example.com
+        documentIndex: 1
+      - equal:
+          path: spec.rules[0].matches[0].path.value
+          value: /b
+        documentIndex: 1
diff --git a/dev/charts/gravitino-iceberg-rest-server/tests/ingress_test.yaml 
b/dev/charts/gravitino-iceberg-rest-server/tests/ingress_test.yaml
index 6e091c7eba..09d9a91f5a 100644
--- a/dev/charts/gravitino-iceberg-rest-server/tests/ingress_test.yaml
+++ b/dev/charts/gravitino-iceberg-rest-server/tests/ingress_test.yaml
@@ -26,6 +26,15 @@ tests:
       - hasDocuments:
           count: 0
 
+  - it: does not render ingress when type is gateway
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+    asserts:
+      - hasDocuments:
+          count: 0
+
   - it: renders networking v1 ingress for supported Kubernetes versions
     release:
       name: iceberg-rest
diff --git a/dev/charts/gravitino-iceberg-rest-server/values.yaml 
b/dev/charts/gravitino-iceberg-rest-server/values.yaml
index 6570d7d728..6e0df95823 100644
--- a/dev/charts/gravitino-iceberg-rest-server/values.yaml
+++ b/dev/charts/gravitino-iceberg-rest-server/values.yaml
@@ -323,6 +323,10 @@ extraVolumeMounts:
 
 ingress:
   enabled: false
+  # Resource type to render when ingress is enabled.
+  # "ingress"  renders a Kubernetes Ingress (apiVersion selected by cluster 
version; default, backward compatible).
+  # "gateway"  renders a Gateway API gateway.networking.k8s.io HTTPRoute 
instead.
+  type: ingress
   className: "nginx"
   annotations: {}
     # kubernetes.io/ingress.class: nginx
@@ -339,6 +343,21 @@ ingress:
   #  - secretName: chart-gravitino-tls
   #    hosts:
   #      - chart-gravitino.local
+  # Gateway API (HTTPRoute) settings. Used only when type is "gateway".
+  # hosts (above) become the HTTPRoute hostnames and rule paths; annotations 
are reused.
+  # In gateway mode each path's pathType is mapped to a Gateway API match type:
+  #   Exact                  -> Exact
+  #   Prefix                 -> PathPrefix
+  #   ImplementationSpecific -> PathPrefix (Gateway API has no equivalent; 
treated as a prefix match)
+  # Any other value fails template rendering (RegularExpression is not 
supported).
+  gateway:
+    # Only gateway.networking.k8s.io/v1 (the GA version) is supported and 
tested.
+    apiVersion: gateway.networking.k8s.io/v1
+    # Parent Gateway(s) this HTTPRoute attaches to.
+    parentRefs: []
+    #  - name: gateway
+    #    namespace: gateway-system
+    #    sectionName: http
 
 
 nodeSelector: {}
diff --git a/dev/charts/gravitino-lance-rest-server/templates/httproute.yaml 
b/dev/charts/gravitino-lance-rest-server/templates/httproute.yaml
new file mode 100644
index 0000000000..92eac5279d
--- /dev/null
+++ b/dev/charts/gravitino-lance-rest-server/templates/httproute.yaml
@@ -0,0 +1,67 @@
+{{- /*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  */}}
+
+{{- if and .Values.ingress.enabled (eq (.Values.ingress.type | default 
"ingress") "gateway") -}}
+{{- $fullName := include "gravitino-lance-rest-server.fullname" . -}}
+{{- $svcPort := .Values.service.port -}}
+{{- $gateway := .Values.ingress.gateway | default dict -}}
+{{- $root := . -}}
+{{- /* Render one HTTPRoute per host so that, like the Ingress, each host only
+   matches its own paths (HTTPRoute hostnames apply to the whole resource). 
*/}}
+{{- range $hostIndex, $hostEntry := .Values.ingress.hosts }}
+{{- if $hostIndex }}
+---
+{{- end }}
+apiVersion: {{ $gateway.apiVersion | default "gateway.networking.k8s.io/v1" }}
+kind: HTTPRoute
+metadata:
+  name: {{ $fullName }}{{ if $hostIndex }}-{{ $hostIndex }}{{ end }}
+  labels:
+    {{- include "gravitino-lance-rest-server.labels" $root | nindent 4 }}
+  {{- with $root.Values.ingress.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+spec:
+  {{- with $gateway.parentRefs }}
+  parentRefs:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+  {{- if $hostEntry.host }}
+  hostnames:
+    - {{ $hostEntry.host | quote }}
+  {{- end }}
+  rules:
+    {{- range $hostEntry.paths }}
+    {{- $pathType := .pathType | default "Prefix" }}
+    {{- if or (eq $pathType "Prefix") (eq $pathType "PathPrefix") (eq 
$pathType "ImplementationSpecific") }}
+    {{- $pathType = "PathPrefix" }}
+    {{- else if ne $pathType "Exact" }}
+    {{- fail (printf "ingress.hosts[].paths[].pathType %q is not supported 
when ingress.type is \"gateway\"; use Exact, Prefix, or ImplementationSpecific" 
$pathType) }}
+    {{- end }}
+    - matches:
+        - path:
+            type: {{ $pathType }}
+            value: {{ .path | quote }}
+      backendRefs:
+        - name: {{ $fullName }}
+          port: {{ $svcPort }}
+    {{- end }}
+{{- end }}
+{{- end }}
diff --git a/dev/charts/gravitino-lance-rest-server/templates/ingress.yaml 
b/dev/charts/gravitino-lance-rest-server/templates/ingress.yaml
index b33c646256..cb6d1292fe 100644
--- a/dev/charts/gravitino-lance-rest-server/templates/ingress.yaml
+++ b/dev/charts/gravitino-lance-rest-server/templates/ingress.yaml
@@ -17,7 +17,7 @@
   under the License.
   */}}
 
-{{- if .Values.ingress.enabled -}}
+{{- if and .Values.ingress.enabled (ne (.Values.ingress.type | default 
"ingress") "gateway") -}}
 {{- $fullName := include "gravitino-lance-rest-server.fullname" . -}}
 {{- $svcPort := .Values.service.port -}}
 {{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" 
.Capabilities.KubeVersion.GitVersion)) }}
diff --git a/dev/charts/gravitino-lance-rest-server/tests/httproute_test.yaml 
b/dev/charts/gravitino-lance-rest-server/tests/httproute_test.yaml
new file mode 100644
index 0000000000..f426aecb15
--- /dev/null
+++ b/dev/charts/gravitino-lance-rest-server/tests/httproute_test.yaml
@@ -0,0 +1,154 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+suite: test gravitino lance rest server httproute
+templates:
+  - httproute.yaml
+tests:
+  - it: does not render httproute by default
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: does not render httproute when type is the default ingress
+    set:
+      ingress:
+        enabled: true
+        type: ingress
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: renders a Gateway API HTTPRoute when type is gateway
+    release:
+      name: lance-rest
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        annotations:
+          example.com/route: "true"
+        hosts:
+          - host: lance-rest.example.com
+            paths:
+              - path: /lance
+                pathType: Prefix
+              - path: /exact
+                pathType: Exact
+        gateway:
+          parentRefs:
+            - name: external
+              namespace: gateway-system
+              sectionName: https
+    asserts:
+      - isAPIVersion:
+          of: gateway.networking.k8s.io/v1
+      - isKind:
+          of: HTTPRoute
+      - equal:
+          path: metadata.name
+          value: lance-rest-gravitino-lance-rest-server-helm
+      - equal:
+          path: metadata.annotations["example.com/route"]
+          value: "true"
+      - equal:
+          path: spec.parentRefs[0].name
+          value: external
+      - equal:
+          path: spec.parentRefs[0].namespace
+          value: gateway-system
+      - equal:
+          path: spec.parentRefs[0].sectionName
+          value: https
+      - contains:
+          path: spec.hostnames
+          content: lance-rest.example.com
+      - equal:
+          path: spec.rules[0].matches[0].path.type
+          value: PathPrefix
+      - equal:
+          path: spec.rules[0].matches[0].path.value
+          value: /lance
+      - equal:
+          path: spec.rules[1].matches[0].path.type
+          value: Exact
+      - equal:
+          path: spec.rules[1].matches[0].path.value
+          value: /exact
+      - equal:
+          path: spec.rules[0].backendRefs[0].name
+          value: lance-rest-gravitino-lance-rest-server-helm
+      - equal:
+          path: spec.rules[0].backendRefs[0].port
+          value: 9101
+
+  - it: maps ImplementationSpecific pathType to PathPrefix in gateway mode
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        hosts:
+          - host: lance-rest.example.com
+            paths:
+              - path: /
+                pathType: ImplementationSpecific
+        gateway:
+          parentRefs:
+            - name: external
+    asserts:
+      - equal:
+          path: spec.rules[0].matches[0].path.type
+          value: PathPrefix
+      - equal:
+          path: spec.rules[0].matches[0].path.value
+          value: /
+
+  - it: defaults pathType to PathPrefix when unset in gateway mode
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        hosts:
+          - host: lance-rest.example.com
+            paths:
+              - path: /api
+        gateway:
+          parentRefs:
+            - name: external
+    asserts:
+      - equal:
+          path: spec.rules[0].matches[0].path.type
+          value: PathPrefix
+
+  - it: fails rendering on an unsupported pathType in gateway mode
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        hosts:
+          - host: lance-rest.example.com
+            paths:
+              - path: /re
+                pathType: RegularExpression
+        gateway:
+          parentRefs:
+            - name: external
+    asserts:
+      - failedTemplate:
+          errorMessage: 'ingress.hosts[].paths[].pathType "RegularExpression" 
is not supported when ingress.type is "gateway"; use Exact, Prefix, or 
ImplementationSpecific'
diff --git a/dev/charts/gravitino-lance-rest-server/tests/ingress_test.yaml 
b/dev/charts/gravitino-lance-rest-server/tests/ingress_test.yaml
index 6afcde56a9..672aaaa3a0 100644
--- a/dev/charts/gravitino-lance-rest-server/tests/ingress_test.yaml
+++ b/dev/charts/gravitino-lance-rest-server/tests/ingress_test.yaml
@@ -26,6 +26,15 @@ tests:
       - hasDocuments:
           count: 0
 
+  - it: does not render ingress when type is gateway
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+    asserts:
+      - hasDocuments:
+          count: 0
+
   - it: renders networking v1 ingress for supported Kubernetes versions
     release:
       name: lance-rest
diff --git a/dev/charts/gravitino-lance-rest-server/values.yaml 
b/dev/charts/gravitino-lance-rest-server/values.yaml
index 2c254b349b..a097d52021 100644
--- a/dev/charts/gravitino-lance-rest-server/values.yaml
+++ b/dev/charts/gravitino-lance-rest-server/values.yaml
@@ -140,6 +140,10 @@ readinessProbe:
 
 ingress:
   enabled: false
+  # Resource type to render when ingress is enabled.
+  # "ingress"  renders a Kubernetes Ingress (apiVersion selected by cluster 
version; default, backward compatible).
+  # "gateway"  renders a Gateway API gateway.networking.k8s.io HTTPRoute 
instead.
+  type: ingress
   className: "nginx"
   annotations: {}
     # kubernetes.io/ingress.class: nginx
@@ -153,6 +157,21 @@ ingress:
   #  - secretName: chart-example-tls
   #    hosts:
   #      - chart-example.local
+  # Gateway API (HTTPRoute) settings. Used only when type is "gateway".
+  # hosts (above) become the HTTPRoute hostnames and rule paths; annotations 
are reused.
+  # In gateway mode each path's pathType is mapped to a Gateway API match type:
+  #   Exact                  -> Exact
+  #   Prefix                 -> PathPrefix
+  #   ImplementationSpecific -> PathPrefix (Gateway API has no equivalent; 
treated as a prefix match)
+  # Any other value fails template rendering (RegularExpression is not 
supported).
+  gateway:
+    # Only gateway.networking.k8s.io/v1 (the GA version) is supported and 
tested.
+    apiVersion: gateway.networking.k8s.io/v1
+    # Parent Gateway(s) this HTTPRoute attaches to.
+    parentRefs: []
+    #  - name: gateway
+    #    namespace: gateway-system
+    #    sectionName: http
 
 ## PodDisruptionBudget settings
 podDisruptionBudget:
diff --git a/dev/charts/gravitino/templates/httproute.yaml 
b/dev/charts/gravitino/templates/httproute.yaml
new file mode 100644
index 0000000000..ed79e5639a
--- /dev/null
+++ b/dev/charts/gravitino/templates/httproute.yaml
@@ -0,0 +1,67 @@
+{{- /*
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  */}}
+
+{{- if and .Values.ingress.enabled (eq (.Values.ingress.type | default 
"ingress") "gateway") -}}
+{{- $fullName := include "gravitino.fullname" . -}}
+{{- $svcPort := .Values.service.port -}}
+{{- $gateway := .Values.ingress.gateway | default dict -}}
+{{- $root := . -}}
+{{- /* Render one HTTPRoute per host so that, like the Ingress, each host only
+   matches its own paths (HTTPRoute hostnames apply to the whole resource). 
*/}}
+{{- range $hostIndex, $hostEntry := .Values.ingress.hosts }}
+{{- if $hostIndex }}
+---
+{{- end }}
+apiVersion: {{ $gateway.apiVersion | default "gateway.networking.k8s.io/v1" }}
+kind: HTTPRoute
+metadata:
+  name: {{ $fullName }}{{ if $hostIndex }}-{{ $hostIndex }}{{ end }}
+  labels:
+    {{- include "gravitino.labels" $root | nindent 4 }}
+  {{- with $root.Values.ingress.annotations }}
+  annotations:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+spec:
+  {{- with $gateway.parentRefs }}
+  parentRefs:
+    {{- toYaml . | nindent 4 }}
+  {{- end }}
+  {{- if $hostEntry.host }}
+  hostnames:
+    - {{ $hostEntry.host | quote }}
+  {{- end }}
+  rules:
+    {{- range $hostEntry.paths }}
+    {{- $pathType := .pathType | default "Prefix" }}
+    {{- if or (eq $pathType "Prefix") (eq $pathType "PathPrefix") (eq 
$pathType "ImplementationSpecific") }}
+    {{- $pathType = "PathPrefix" }}
+    {{- else if ne $pathType "Exact" }}
+    {{- fail (printf "ingress.hosts[].paths[].pathType %q is not supported 
when ingress.type is \"gateway\"; use Exact, Prefix, or ImplementationSpecific" 
$pathType) }}
+    {{- end }}
+    - matches:
+        - path:
+            type: {{ $pathType }}
+            value: {{ .path | quote }}
+      backendRefs:
+        - name: {{ $fullName }}
+          port: {{ $svcPort }}
+    {{- end }}
+{{- end }}
+{{- end }}
diff --git a/dev/charts/gravitino/templates/ingress.yaml 
b/dev/charts/gravitino/templates/ingress.yaml
index 64252ee814..f40947b3d0 100644
--- a/dev/charts/gravitino/templates/ingress.yaml
+++ b/dev/charts/gravitino/templates/ingress.yaml
@@ -6,7 +6,7 @@
     to you under the Apache License, Version 2.0 (the
   "License"); you may not use this file except in compliance
   with the License.  You may obtain a copy of the License at
-  
+
   http://www.apache.org/licenses/LICENSE-2.0
 
   Unless required by applicable law or agreed to in writing,
@@ -17,7 +17,7 @@
   under the License.
   */}}
 
-  {{- if .Values.ingress.enabled -}}
+{{- if and .Values.ingress.enabled (ne (.Values.ingress.type | default 
"ingress") "gateway") -}}
 {{- $fullName := include "gravitino.fullname" . -}}
 {{- $svcPort := .Values.service.port -}}
 {{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" 
.Capabilities.KubeVersion.GitVersion)) }}
diff --git a/dev/charts/gravitino/tests/httproute_test.yaml 
b/dev/charts/gravitino/tests/httproute_test.yaml
new file mode 100644
index 0000000000..baadc31c80
--- /dev/null
+++ b/dev/charts/gravitino/tests/httproute_test.yaml
@@ -0,0 +1,154 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#  http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+suite: test gravitino httproute
+templates:
+  - httproute.yaml
+tests:
+  - it: does not render httproute by default
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: does not render httproute when type is the default ingress
+    set:
+      ingress:
+        enabled: true
+        type: ingress
+    asserts:
+      - hasDocuments:
+          count: 0
+
+  - it: renders a Gateway API HTTPRoute when type is gateway
+    release:
+      name: gravitino
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        annotations:
+          example.com/route: "true"
+        hosts:
+          - host: gravitino.example.com
+            paths:
+              - path: /gravitino
+                pathType: Prefix
+              - path: /exact
+                pathType: Exact
+        gateway:
+          parentRefs:
+            - name: external
+              namespace: gateway-system
+              sectionName: https
+    asserts:
+      - isAPIVersion:
+          of: gateway.networking.k8s.io/v1
+      - isKind:
+          of: HTTPRoute
+      - equal:
+          path: metadata.name
+          value: gravitino-gravitino-helm
+      - equal:
+          path: metadata.annotations["example.com/route"]
+          value: "true"
+      - equal:
+          path: spec.parentRefs[0].name
+          value: external
+      - equal:
+          path: spec.parentRefs[0].namespace
+          value: gateway-system
+      - equal:
+          path: spec.parentRefs[0].sectionName
+          value: https
+      - contains:
+          path: spec.hostnames
+          content: gravitino.example.com
+      - equal:
+          path: spec.rules[0].matches[0].path.type
+          value: PathPrefix
+      - equal:
+          path: spec.rules[0].matches[0].path.value
+          value: /gravitino
+      - equal:
+          path: spec.rules[1].matches[0].path.type
+          value: Exact
+      - equal:
+          path: spec.rules[1].matches[0].path.value
+          value: /exact
+      - equal:
+          path: spec.rules[0].backendRefs[0].name
+          value: gravitino-gravitino-helm
+      - equal:
+          path: spec.rules[0].backendRefs[0].port
+          value: 8090
+
+  - it: maps ImplementationSpecific pathType to PathPrefix in gateway mode
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        hosts:
+          - host: gravitino.example.com
+            paths:
+              - path: /
+                pathType: ImplementationSpecific
+        gateway:
+          parentRefs:
+            - name: external
+    asserts:
+      - equal:
+          path: spec.rules[0].matches[0].path.type
+          value: PathPrefix
+      - equal:
+          path: spec.rules[0].matches[0].path.value
+          value: /
+
+  - it: defaults pathType to PathPrefix when unset in gateway mode
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        hosts:
+          - host: gravitino.example.com
+            paths:
+              - path: /api
+        gateway:
+          parentRefs:
+            - name: external
+    asserts:
+      - equal:
+          path: spec.rules[0].matches[0].path.type
+          value: PathPrefix
+
+  - it: fails rendering on an unsupported pathType in gateway mode
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+        hosts:
+          - host: gravitino.example.com
+            paths:
+              - path: /re
+                pathType: RegularExpression
+        gateway:
+          parentRefs:
+            - name: external
+    asserts:
+      - failedTemplate:
+          errorMessage: 'ingress.hosts[].paths[].pathType "RegularExpression" 
is not supported when ingress.type is "gateway"; use Exact, Prefix, or 
ImplementationSpecific'
diff --git a/dev/charts/gravitino/tests/ingress_test.yaml 
b/dev/charts/gravitino/tests/ingress_test.yaml
index 6591cf535c..5c577877bc 100644
--- a/dev/charts/gravitino/tests/ingress_test.yaml
+++ b/dev/charts/gravitino/tests/ingress_test.yaml
@@ -26,6 +26,15 @@ tests:
       - hasDocuments:
           count: 0
 
+  - it: does not render ingress when type is gateway
+    set:
+      ingress:
+        enabled: true
+        type: gateway
+    asserts:
+      - hasDocuments:
+          count: 0
+
   - it: renders networking v1 ingress for supported Kubernetes versions
     release:
       name: gravitino
diff --git a/dev/charts/gravitino/values.yaml b/dev/charts/gravitino/values.yaml
index fb14537b66..b2796bc09f 100644
--- a/dev/charts/gravitino/values.yaml
+++ b/dev/charts/gravitino/values.yaml
@@ -514,6 +514,10 @@ extraExposePorts:
 
 ingress:
   enabled: false
+  # Resource type to render when ingress is enabled.
+  # "ingress"  renders a Kubernetes Ingress (apiVersion selected by cluster 
version; default, backward compatible).
+  # "gateway"  renders a Gateway API gateway.networking.k8s.io HTTPRoute 
instead.
+  type: ingress
   className: "nginx"
   annotations: {}
   # kubernetes.io/tls-acme: "true"
@@ -526,6 +530,21 @@ ingress:
   #  - secretName: chart-gravitino-tls
   #    hosts:
   #      - chart-gravitino.local
+  # Gateway API (HTTPRoute) settings. Used only when type is "gateway".
+  # hosts (above) become the HTTPRoute hostnames and rule paths; annotations 
are reused.
+  # In gateway mode each path's pathType is mapped to a Gateway API match type:
+  #   Exact                  -> Exact
+  #   Prefix                 -> PathPrefix
+  #   ImplementationSpecific -> PathPrefix (Gateway API has no equivalent; 
treated as a prefix match)
+  # Any other value fails template rendering (RegularExpression is not 
supported).
+  gateway:
+    # Only gateway.networking.k8s.io/v1 (the GA version) is supported and 
tested.
+    apiVersion: gateway.networking.k8s.io/v1
+    # Parent Gateway(s) this HTTPRoute attaches to.
+    parentRefs: []
+    #  - name: gateway
+    #    namespace: gateway-system
+    #    sectionName: http
 
 ## Deployment annotations
 ##


Reply via email to