diff --git a/internal/controller/indexer/indexer.go b/internal/controller/indexer/indexer.go index 0acdf693b..1ba3a4d8c 100644 --- a/internal/controller/indexer/indexer.go +++ b/internal/controller/indexer/indexer.go @@ -890,6 +890,7 @@ func IngressClassParametersRefIndexFunc(rawObj client.Object) []string { ingressClass.Spec.Parameters.Kind == internaltypes.KindGatewayProxy { namespace := k8sutils.GetIngressClassParametersNamespace(*ingressClass) return []string{GenIndexKey(namespace, ingressClass.Spec.Parameters.Name)} +<<<<<<< HEAD } return nil } @@ -903,6 +904,8 @@ func IngressClassV1beta1ParametersRefIndexFunc(rawObj client.Object) []string { ingressClass.Spec.Parameters.Kind == internaltypes.KindGatewayProxy { namespace := k8sutils.GetIngressClassV1beta1ParametersNamespace(*ingressClass) return []string{GenIndexKey(namespace, ingressClass.Spec.Parameters.Name)} +======= +>>>>>>> b52c26c8 (feat: support custom gatewayproxy namespace for ingressclass (#2701)) } return nil } diff --git a/internal/controller/ingressclass_controller.go b/internal/controller/ingressclass_controller.go index b0cea10e9..f92ed7226 100644 --- a/internal/controller/ingressclass_controller.go +++ b/internal/controller/ingressclass_controller.go @@ -173,3 +173,71 @@ func (r *IngressClassReconciler) listIngressClassesForSecret(ctx context.Context return distinctRequests(requests) } +<<<<<<< HEAD +======= + +func (r *IngressClassReconciler) processInfrastructure(tctx *provider.TranslateContext, ingressClass *networkingv1.IngressClass) error { + if ingressClass.Spec.Parameters == nil { + return nil + } + + if ingressClass.Spec.Parameters.APIGroup == nil || + *ingressClass.Spec.Parameters.APIGroup != v1alpha1.GroupVersion.Group || + ingressClass.Spec.Parameters.Kind != KindGatewayProxy { + return nil + } + + namespace := utils.GetIngressClassParametersNamespace(*ingressClass) + + gatewayProxy := new(v1alpha1.GatewayProxy) + if err := r.Get(context.Background(), client.ObjectKey{ + Namespace: namespace, + Name: ingressClass.Spec.Parameters.Name, + }, gatewayProxy); err != nil { + return fmt.Errorf("failed to get gateway proxy: %w", err) + } + + rk := utils.NamespacedNameKind(ingressClass) + + tctx.GatewayProxies[rk] = *gatewayProxy + tctx.ResourceParentRefs[rk] = append(tctx.ResourceParentRefs[rk], rk) + + // Load secrets if needed + if gatewayProxy.Spec.Provider != nil && gatewayProxy.Spec.Provider.ControlPlane != nil { + auth := gatewayProxy.Spec.Provider.ControlPlane.Auth + if auth.Type == v1alpha1.AuthTypeAdminKey && auth.AdminKey != nil && auth.AdminKey.ValueFrom != nil { + if auth.AdminKey.ValueFrom.SecretKeyRef != nil { + secretRef := auth.AdminKey.ValueFrom.SecretKeyRef + secret := &corev1.Secret{} + if err := r.Get(context.Background(), client.ObjectKey{ + Namespace: namespace, + Name: secretRef.Name, + }, secret); err != nil { + r.Log.Error(err, "failed to get secret for gateway proxy", "namespace", namespace, "name", secretRef.Name) + return err + } + tctx.Secrets[client.ObjectKey{ + Namespace: namespace, + Name: secretRef.Name, + }] = secret + } + } + } + + if service := gatewayProxy.Spec.Provider.ControlPlane.Service; service != nil { + if err := addProviderEndpointsToTranslateContext(tctx, r.Client, r.Log, types.NamespacedName{ + Namespace: gatewayProxy.GetNamespace(), + Name: service.Name, + }); err != nil { + return err + } + } + + _, ok := tctx.GatewayProxies[rk] + if !ok { + return fmt.Errorf("no gateway proxy found for ingress class") + } + + return nil +} +>>>>>>> b52c26c8 (feat: support custom gatewayproxy namespace for ingressclass (#2701)) diff --git a/internal/controller/utils.go b/internal/controller/utils.go index f34f01a45..e2db71dc7 100644 --- a/internal/controller/utils.go +++ b/internal/controller/utils.go @@ -1733,7 +1733,10 @@ func GetGatewayProxyByIngressClass(ctx context.Context, r client.Client, ingress return nil, nil } +<<<<<<< HEAD // Use utility function to get namespace, which handles annotation fallback +======= +>>>>>>> b52c26c8 (feat: support custom gatewayproxy namespace for ingressclass (#2701)) namespace := utils.GetIngressClassParametersNamespace(*ingressClass) gatewayProxy := new(v1alpha1.GatewayProxy) diff --git a/internal/utils/k8s.go b/internal/utils/k8s.go index 55ea03eff..f04cbd346 100644 --- a/internal/utils/k8s.go +++ b/internal/utils/k8s.go @@ -22,7 +22,10 @@ import ( "regexp" networkingv1 "k8s.io/api/networking/v1" +<<<<<<< HEAD networkingv1beta1 "k8s.io/api/networking/v1beta1" +======= +>>>>>>> b52c26c8 (feat: support custom gatewayproxy namespace for ingressclass (#2701)) metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" k8stypes "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" @@ -112,6 +115,7 @@ func GetIngressClassParametersNamespace(ingressClass networkingv1.IngressClass) } return namespace } +<<<<<<< HEAD func GetIngressClassV1beta1ParametersNamespace(ingressClass networkingv1beta1.IngressClass) string { namespace := "default" @@ -123,3 +127,5 @@ func GetIngressClassV1beta1ParametersNamespace(ingressClass networkingv1beta1.In } return namespace } +======= +>>>>>>> b52c26c8 (feat: support custom gatewayproxy namespace for ingressclass (#2701)) diff --git a/internal/webhook/v1/ingressclass_webhook.go b/internal/webhook/v1/ingressclass_webhook.go index 4d77fe8a5..67d2c3604 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 7b197e107..5cca40b38 100644 --- a/test/e2e/crds/v2/basic.go +++ b/test/e2e/crds/v2/basic.go @@ -121,4 +121,81 @@ spec: Eventually(request).WithArguments("/headers").WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusNotFound)) }) }) + + 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)) + }) + }) })