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

ronething pushed a commit to branch v2.0.0
in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git

commit b01b71b90fb48f19df1f95172ca09c581b1e11b7
Author: Ashing Zheng <[email protected]>
AuthorDate: Mon Jan 12 14:26:13 2026 +0800

    feat: support custom gatewayproxy namespace for ingressclass (#2701)
    
    Signed-off-by: Ashing Zheng <[email protected]>
    (cherry picked from commit b52c26c8519389600c968c497533c6a6cf9d485d)
---
 internal/controller/indexer/indexer.go         |  8 +--
 internal/controller/ingressclass_controller.go |  5 +-
 internal/controller/utils.go                   | 10 +--
 internal/utils/k8s.go                          | 12 ++++
 internal/webhook/v1/ingressclass_webhook.go    |  6 +-
 test/e2e/crds/v2/basic.go                      | 91 +++++++++++++++++++++++++-
 6 files changed, 109 insertions(+), 23 deletions(-)

diff --git a/internal/controller/indexer/indexer.go 
b/internal/controller/indexer/indexer.go
index 91bec714..6f0d66a4 100644
--- a/internal/controller/indexer/indexer.go
+++ b/internal/controller/indexer/indexer.go
@@ -34,6 +34,7 @@ import (
        apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
        
"github.com/apache/apisix-ingress-controller/internal/adc/translator/annotations"
        internaltypes 
"github.com/apache/apisix-ingress-controller/internal/types"
+       k8sutils "github.com/apache/apisix-ingress-controller/internal/utils"
        "github.com/apache/apisix-ingress-controller/pkg/utils"
 )
 
@@ -859,11 +860,8 @@ func IngressClassParametersRefIndexFunc(rawObj 
client.Object) []string {
                ingressClass.Spec.Parameters.APIGroup != nil &&
                *ingressClass.Spec.Parameters.APIGroup == 
v1alpha1.GroupVersion.Group &&
                ingressClass.Spec.Parameters.Kind == 
internaltypes.KindGatewayProxy {
-               ns := ingressClass.GetNamespace()
-               if ingressClass.Spec.Parameters.Namespace != nil {
-                       ns = *ingressClass.Spec.Parameters.Namespace
-               }
-               return []string{GenIndexKey(ns, 
ingressClass.Spec.Parameters.Name)}
+               namespace := 
k8sutils.GetIngressClassParametersNamespace(*ingressClass)
+               return []string{GenIndexKey(namespace, 
ingressClass.Spec.Parameters.Name)}
        }
        return nil
 }
diff --git a/internal/controller/ingressclass_controller.go 
b/internal/controller/ingressclass_controller.go
index 5594ee6c..0afbf6f2 100644
--- a/internal/controller/ingressclass_controller.go
+++ b/internal/controller/ingressclass_controller.go
@@ -187,10 +187,7 @@ func (r *IngressClassReconciler) 
processInfrastructure(tctx *provider.TranslateC
                return nil
        }
 
-       namespace := ingressClass.Namespace
-       if ingressClass.Spec.Parameters.Namespace != nil {
-               namespace = *ingressClass.Spec.Parameters.Namespace
-       }
+       namespace := utils.GetIngressClassParametersNamespace(*ingressClass)
 
        gatewayProxy := new(v1alpha1.GatewayProxy)
        if err := r.Get(context.Background(), client.ObjectKey{
diff --git a/internal/controller/utils.go b/internal/controller/utils.go
index 892d027c..a00ef916 100644
--- a/internal/controller/utils.go
+++ b/internal/controller/utils.go
@@ -1354,10 +1354,7 @@ func ProcessIngressClassParameters(tctx 
*provider.TranslateContext, c client.Cli
        parameters := ingressClass.Spec.Parameters
        // check if the parameters reference GatewayProxy
        if parameters.APIGroup != nil && *parameters.APIGroup == 
v1alpha1.GroupVersion.Group && parameters.Kind == KindGatewayProxy {
-               ns := object.GetNamespace()
-               if parameters.Namespace != nil {
-                       ns = *parameters.Namespace
-               }
+               ns := utils.GetIngressClassParametersNamespace(*ingressClass)
 
                gatewayProxy := &v1alpha1.GatewayProxy{}
                if err := c.Get(tctx, client.ObjectKey{
@@ -1553,10 +1550,7 @@ func GetGatewayProxyByIngressClass(ctx context.Context, 
r client.Client, ingress
                return nil, nil
        }
 
-       namespace := ingressClass.Namespace
-       if ingressClass.Spec.Parameters.Namespace != nil {
-               namespace = *ingressClass.Spec.Parameters.Namespace
-       }
+       namespace := utils.GetIngressClassParametersNamespace(*ingressClass)
 
        gatewayProxy := new(v1alpha1.GatewayProxy)
        if err := r.Get(ctx, client.ObjectKey{
diff --git a/internal/utils/k8s.go b/internal/utils/k8s.go
index 0bca19d0..0d58f301 100644
--- a/internal/utils/k8s.go
+++ b/internal/utils/k8s.go
@@ -21,6 +21,7 @@ import (
        "net"
        "regexp"
 
+       networkingv1 "k8s.io/api/networking/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        k8stypes "k8s.io/apimachinery/pkg/types"
        "sigs.k8s.io/controller-runtime/pkg/client"
@@ -99,3 +100,14 @@ func ConditionStatus(status bool) metav1.ConditionStatus {
        }
        return metav1.ConditionFalse
 }
+
+func GetIngressClassParametersNamespace(ingressClass 
networkingv1.IngressClass) string {
+       namespace := "default"
+       if ingressClass.Spec.Parameters.Namespace != nil {
+               namespace = *ingressClass.Spec.Parameters.Namespace
+       }
+       if annotationNamespace, exists := 
ingressClass.Annotations["apisix.apache.org/parameters-namespace"]; exists && 
annotationNamespace != "" {
+               namespace = annotationNamespace
+       }
+       return namespace
+}
diff --git a/internal/webhook/v1/ingressclass_webhook.go 
b/internal/webhook/v1/ingressclass_webhook.go
index 4d77fe8a..67d2c360 100644
--- a/internal/webhook/v1/ingressclass_webhook.go
+++ b/internal/webhook/v1/ingressclass_webhook.go
@@ -31,6 +31,7 @@ import (
        v1alpha1 "github.com/apache/apisix-ingress-controller/api/v1alpha1"
        "github.com/apache/apisix-ingress-controller/internal/controller/config"
        internaltypes 
"github.com/apache/apisix-ingress-controller/internal/types"
+       "github.com/apache/apisix-ingress-controller/internal/utils"
 )
 
 // nolint:unused
@@ -106,10 +107,7 @@ func (v *IngressClassCustomValidator) 
warnIfMissingGatewayProxyForIngressClass(c
                return nil
        }
 
-       ns := ingressClass.GetNamespace()
-       if params.Namespace != nil && *params.Namespace != "" {
-               ns = *params.Namespace
-       }
+       ns := utils.GetIngressClassParametersNamespace(*ingressClass)
        name := params.Name
 
        var gp v1alpha1.GatewayProxy
diff --git a/test/e2e/crds/v2/basic.go b/test/e2e/crds/v2/basic.go
index 36205d5c..65415340 100644
--- a/test/e2e/crds/v2/basic.go
+++ b/test/e2e/crds/v2/basic.go
@@ -18,16 +18,26 @@
 package v2
 
 import (
+       "fmt"
+       "net/http"
+       "time"
+
        . "github.com/onsi/ginkgo/v2"
        . "github.com/onsi/gomega"
+       "k8s.io/apimachinery/pkg/types"
 
+       apiv2 "github.com/apache/apisix-ingress-controller/api/v2"
+       "github.com/apache/apisix-ingress-controller/test/e2e/framework"
        "github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
 )
 
 var _ = Describe("APISIX Standalone Basic Tests", Label("apisix.apache.org", 
"v2", "basic"), func() {
-       s := scaffold.NewDefaultScaffold()
+       var (
+               s       = scaffold.NewDefaultScaffold()
+               applier = framework.NewApplier(s.GinkgoT, s.K8sClient, 
s.CreateResourceFromString)
+       )
 
-       Describe("APISIX HTTP Proxy", func() {
+       Context("APISIX HTTP Proxy", func() {
                It("should handle basic HTTP requests", func() {
                        httpClient := s.NewAPISIXClient()
                        Expect(httpClient).NotTo(BeNil())
@@ -52,4 +62,81 @@ var _ = Describe("APISIX Standalone Basic Tests", 
Label("apisix.apache.org", "v2
                })
 
        })
+
+       Context("IngressClass Annotations", func() {
+               It("Basic tests", func() {
+                       const ingressClassYaml = `
+apiVersion: networking.k8s.io/v1
+kind: IngressClass
+metadata:
+  name: %s
+  annotations:
+    apisix.apache.org/parameters-namespace: %s
+spec:
+  controller: %s
+  parameters:
+    apiGroup: apisix.apache.org
+    kind: GatewayProxy
+    name: apisix-proxy-config
+`
+
+                       By("create GatewayProxy")
+
+                       err := 
s.CreateResourceFromString(s.GetGatewayProxySpec())
+                       Expect(err).NotTo(HaveOccurred(), "creating 
GatewayProxy")
+                       time.Sleep(5 * time.Second)
+
+                       By("create IngressClass")
+                       ingressClass := fmt.Sprintf(ingressClassYaml, 
s.Namespace(), s.Namespace(), s.GetControllerName())
+                       err = s.CreateResourceFromString(ingressClass)
+                       Expect(err).NotTo(HaveOccurred(), "creating 
IngressClass")
+                       time.Sleep(5 * time.Second)
+
+                       const apisixRouteSpec = `
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+  name: default
+spec:
+  ingressClassName: %s
+  http:
+  - name: rule0
+    match:
+      hosts:
+      - httpbin
+      paths:
+      - %s
+    backends:
+    - serviceName: httpbin-service-e2e-test
+      servicePort: 80
+`
+                       request := func(path string) int {
+                               return 
s.NewAPISIXClient().GET(path).WithHost("httpbin").Expect().Raw().StatusCode
+                       }
+
+                       By("apply ApisixRoute")
+                       var apisixRoute apiv2.ApisixRoute
+                       applier.MustApplyAPIv2(types.NamespacedName{Namespace: 
s.Namespace(), Name: "default"}, &apisixRoute,
+                               fmt.Sprintf(apisixRouteSpec, s.Namespace(), 
"/get"))
+
+                       By("verify ApisixRoute works")
+                       Eventually(request).WithArguments("/get").WithTimeout(8 
* time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusOK))
+
+                       By("update ApisixRoute")
+                       applier.MustApplyAPIv2(types.NamespacedName{Namespace: 
s.Namespace(), Name: "default"}, &apisixRoute,
+                               fmt.Sprintf(apisixRouteSpec, s.Namespace(), 
"/headers"))
+                       Eventually(request).WithArguments("/get").WithTimeout(8 
* time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound))
+                       s.RequestAssert(&scaffold.RequestAssert{
+                               Method: "GET",
+                               Path:   "/headers",
+                               Host:   "httpbin",
+                               Check:  
scaffold.WithExpectedStatus(http.StatusOK),
+                       })
+
+                       By("delete ApisixRoute")
+                       err = s.DeleteResource("ApisixRoute", "default")
+                       Expect(err).ShouldNot(HaveOccurred(), "deleting 
ApisixRoute")
+                       
Eventually(request).WithArguments("/headers").WithTimeout(8 * 
time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound))
+               })
+       })
 })

Reply via email to