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)) + }) + }) })
