From 2fc258a4060d0799d8b666b708707b94b1b4d754 Mon Sep 17 00:00:00 2001 From: ashing Date: Wed, 23 Apr 2025 15:30:34 +0800 Subject: [PATCH 1/6] (WIP) feat: support sync when update gateway proxy Signed-off-by: ashing --- internal/controller/consumer_controller.go | 46 ++++++++++++ internal/controller/httproute_controller.go | 48 +++++++++++++ internal/controller/indexer/indexer.go | 45 +++++++++--- internal/controller/ingress_controller.go | 80 ++++++++++++--------- 4 files changed, 178 insertions(+), 41 deletions(-) diff --git a/internal/controller/consumer_controller.go b/internal/controller/consumer_controller.go index 4ea7e3325..17f29d659 100644 --- a/internal/controller/consumer_controller.go +++ b/internal/controller/consumer_controller.go @@ -62,6 +62,9 @@ func (r *ConsumerReconciler) SetupWithManager(mgr ctrl.Manager) error { Watches(&corev1.Secret{}, handler.EnqueueRequestsFromMapFunc(r.listConsumersForSecret), ). + Watches(&v1alpha1.GatewayProxy{}, + handler.EnqueueRequestsFromMapFunc(r.listConsumersForGatewayProxy), + ). Complete(r) } @@ -115,6 +118,49 @@ func (r *ConsumerReconciler) listConsumersForGateway(ctx context.Context, obj cl return requests } +func (r *ConsumerReconciler) listConsumersForGatewayProxy(ctx context.Context, obj client.Object) []reconcile.Request { + gatewayProxy, ok := obj.(*v1alpha1.GatewayProxy) + if !ok { + r.Log.Error(nil, "failed to convert to GatewayProxy", "object", obj) + return nil + } + + namespace := gatewayProxy.GetNamespace() + name := gatewayProxy.GetName() + + // find all gateways that reference this gateway proxy + gatewayList := &gatewayv1.GatewayList{} + if err := r.List(ctx, gatewayList, client.MatchingFields{ + indexer.ParametersRef: indexer.GenIndexKey(namespace, name), + }); err != nil { + r.Log.Error(err, "failed to list gateways for gateway proxy", "gatewayproxy", gatewayProxy.GetName()) + return nil + } + + var requests []reconcile.Request + + for _, gateway := range gatewayList.Items { + consumerList := &v1alpha1.ConsumerList{} + if err := r.List(ctx, consumerList, client.MatchingFields{ + indexer.ConsumerGatewayRef: indexer.GenIndexKey(gateway.Namespace, gateway.Name), + }); err != nil { + r.Log.Error(err, "failed to list consumers for gateway", "gateway", gateway.Name) + continue + } + + for _, consumer := range consumerList.Items { + requests = append(requests, reconcile.Request{ + NamespacedName: client.ObjectKey{ + Namespace: consumer.Namespace, + Name: consumer.Name, + }, + }) + } + } + + return requests +} + func (r *ConsumerReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { consumer := new(v1alpha1.Consumer) if err := r.Get(ctx, req.NamespacedName, consumer); err != nil { diff --git a/internal/controller/httproute_controller.go b/internal/controller/httproute_controller.go index f4f9b7f60..16655b42d 100644 --- a/internal/controller/httproute_controller.go +++ b/internal/controller/httproute_controller.go @@ -82,6 +82,9 @@ func (r *HTTPRouteReconciler) SetupWithManager(mgr ctrl.Manager) error { handler.EnqueueRequestsFromMapFunc(r.listHTTPRouteByHTTPRoutePolicy), builder.WithPredicates(httpRoutePolicyPredicateFuncs(r.genericEvent)), ). + Watches(&v1alpha1.GatewayProxy{}, + handler.EnqueueRequestsFromMapFunc(r.listHTTPRoutesForGatewayProxy), + ). WatchesRawSource( source.Channel( r.genericEvent, @@ -535,3 +538,48 @@ func httpRoutePolicyPredicateFuncs(channel chan event.GenericEvent) predicate.Pr }, } } + +// listHTTPRoutesForGatewayProxy list all HTTPRoute resources that are affected by a given GatewayProxy +func (r *HTTPRouteReconciler) listHTTPRoutesForGatewayProxy(ctx context.Context, obj client.Object) []reconcile.Request { + gatewayProxy, ok := obj.(*v1alpha1.GatewayProxy) + if !ok { + r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to GatewayProxy") + return nil + } + + namespace := gatewayProxy.GetNamespace() + name := gatewayProxy.GetName() + + // find all gateways that reference this gateway proxy + gatewayList := &gatewayv1.GatewayList{} + if err := r.List(ctx, gatewayList, client.MatchingFields{ + indexer.ParametersRef: indexer.GenIndexKey(namespace, name), + }); err != nil { + r.Log.Error(err, "failed to list gateways for gateway proxy", "gatewayproxy", gatewayProxy.GetName()) + return nil + } + + var requests []reconcile.Request + + // for each gateway, find all HTTPRoute resources that reference it + for _, gateway := range gatewayList.Items { + httpRouteList := &gatewayv1.HTTPRouteList{} + if err := r.List(ctx, httpRouteList, client.MatchingFields{ + indexer.ParentRefs: indexer.GenIndexKey(gateway.Namespace, gateway.Name), + }); err != nil { + r.Log.Error(err, "failed to list httproutes for gateway", "gateway", gateway.Name) + continue + } + + for _, httpRoute := range httpRouteList.Items { + requests = append(requests, reconcile.Request{ + NamespacedName: client.ObjectKey{ + Namespace: httpRoute.Namespace, + Name: httpRoute.Name, + }, + }) + } + } + + return requests +} diff --git a/internal/controller/indexer/indexer.go b/internal/controller/indexer/indexer.go index 7a606b274..fadfd03a3 100644 --- a/internal/controller/indexer/indexer.go +++ b/internal/controller/indexer/indexer.go @@ -14,15 +14,16 @@ import ( ) const ( - ServiceIndexRef = "serviceRefs" - ExtensionRef = "extensionRef" - ParametersRef = "parametersRef" - ParentRefs = "parentRefs" - IngressClass = "ingressClass" - SecretIndexRef = "secretRefs" - IngressClassRef = "ingressClassRef" - ConsumerGatewayRef = "consumerGatewayRef" - PolicyTargetRefs = "targetRefs" + ServiceIndexRef = "serviceRefs" + ExtensionRef = "extensionRef" + ParametersRef = "parametersRef" + ParentRefs = "parentRefs" + IngressClass = "ingressClass" + SecretIndexRef = "secretRefs" + IngressClassRef = "ingressClassRef" + IngressClassParametersRef = "ingressClassParametersRef" + ConsumerGatewayRef = "consumerGatewayRef" + PolicyTargetRefs = "targetRefs" ) func SetupIndexer(mgr ctrl.Manager) error { @@ -189,6 +190,16 @@ func setupIngressIndexer(mgr ctrl.Manager) error { return err } + // create IngressClassParametersRef index + if err := mgr.GetFieldIndexer().IndexField( + context.Background(), + &networkingv1.IngressClass{}, + IngressClassParametersRef, + IngressClassParametersRefIndexFunc, + ); err != nil { + return err + } + return nil } @@ -366,3 +377,19 @@ func BackendTrafficPolicyIndexFunc(rawObj client.Object) []string { } return keys } + +func IngressClassParametersRefIndexFunc(rawObj client.Object) []string { + ingressClass := rawObj.(*networkingv1.IngressClass) + // check if the IngressClass references this gateway proxy + if ingressClass.Spec.Parameters != nil && + ingressClass.Spec.Parameters.APIGroup != nil && + *ingressClass.Spec.Parameters.APIGroup == v1alpha1.GroupVersion.Group && + ingressClass.Spec.Parameters.Kind == "GatewayProxy" { + ns := ingressClass.GetNamespace() + if ingressClass.Spec.Parameters.Namespace != nil { + ns = *ingressClass.Spec.Parameters.Namespace + } + return []string{GenIndexKey(ns, ingressClass.Spec.Parameters.Name)} + } + return nil +} diff --git a/internal/controller/ingress_controller.go b/internal/controller/ingress_controller.go index 8a49b00c5..88aa5b96d 100644 --- a/internal/controller/ingress_controller.go +++ b/internal/controller/ingress_controller.go @@ -83,6 +83,9 @@ func (r *IngressReconciler) SetupWithManager(mgr ctrl.Manager) error { handler.EnqueueRequestsFromMapFunc(r.listIngressesByHTTPRoutePolicy), builder.WithPredicates(httpRoutePolicyPredicateFuncs(r.genericEvent)), ). + Watches(&v1alpha1.GatewayProxy{}, + handler.EnqueueRequestsFromMapFunc(r.listIngressesForGatewayProxy), + ). WatchesRawSource( source.Channel( r.genericEvent, @@ -219,38 +222,8 @@ func (r *IngressReconciler) getIngressClass(obj client.Object) (*networkingv1.In // checkIngressClass check if the ingress uses the ingress class that we control func (r *IngressReconciler) checkIngressClass(obj client.Object) bool { - ingress := obj.(*networkingv1.Ingress) - - if ingress.Spec.IngressClassName == nil { - // handle the case where IngressClassName is not specified - // find all ingress classes and check if any of them is marked as default - ingressClassList := &networkingv1.IngressClassList{} - if err := r.List(context.Background(), ingressClassList, client.MatchingFields{ - indexer.IngressClass: config.GetControllerName(), - }); err != nil { - r.Log.Error(err, "failed to list ingress classes") - return false - } - - // find the ingress class that is marked as default - for _, ic := range ingressClassList.Items { - if IsDefaultIngressClass(&ic) && matchesController(ic.Spec.Controller) { - log.Debugw("match the default ingress class") - return true - } - } - - log.Debugw("no default ingress class found") - return false - } - - // check if the ingress class is controlled by us - ingressClass := networkingv1.IngressClass{} - if err := r.Client.Get(context.Background(), client.ObjectKey{Name: *ingress.Spec.IngressClassName}, &ingressClass); err != nil { - return false - } - - return matchesController(ingressClass.Spec.Controller) + _, err := r.getIngressClass(obj) + return err == nil } // matchesIngressController check if the ingress class is controlled by us @@ -735,3 +708,46 @@ func (r *IngressReconciler) processIngressClassParameters(ctx context.Context, t return nil } + +// listIngressesForGatewayProxy list all ingresses that use a specific gateway proxy +func (r *IngressReconciler) listIngressesForGatewayProxy(ctx context.Context, obj client.Object) []reconcile.Request { + gatewayProxy, ok := obj.(*v1alpha1.GatewayProxy) + if !ok { + r.Log.Error(fmt.Errorf("unexpected object type"), "failed to convert object to GatewayProxy") + return nil + } + + // find all ingress classes that reference this gateway proxy + ingressClassList := &networkingv1.IngressClassList{} + if err := r.List(ctx, ingressClassList, client.MatchingFields{ + indexer.IngressClassParametersRef: indexer.GenIndexKey(gatewayProxy.GetNamespace(), gatewayProxy.GetName()), + }); err != nil { + r.Log.Error(err, "failed to list ingress classes for gateway proxy", "gatewayproxy", gatewayProxy.GetName()) + return nil + } + + var requests []reconcile.Request + + for _, ingressClass := range ingressClassList.Items { + requests = append(requests, r.listIngressForIngressClass(ctx, &ingressClass)...) + } + + // the requests may contain duplicates, distinct the requests + requests = distinctRequests(requests) + + return requests +} + +// distinctRequests distinct the requests +func distinctRequests(requests []reconcile.Request) []reconcile.Request { + uniqueRequests := make(map[string]reconcile.Request) + for _, request := range requests { + uniqueRequests[request.String()] = request + } + + distinctRequests := make([]reconcile.Request, 0, len(uniqueRequests)) + for _, request := range uniqueRequests { + distinctRequests = append(distinctRequests, request) + } + return distinctRequests +} From d80c0f2f9bee1ca4a08e73bd3ac509eadf7d3f8f Mon Sep 17 00:00:00 2001 From: ashing Date: Thu, 24 Apr 2025 19:06:52 +0800 Subject: [PATCH 2/6] fix: add test case Signed-off-by: ashing --- .gitignore | 2 +- Makefile | 9 +++ internal/provider/adc/adc.go | 17 ++--- test/e2e/crds/consumer.go | 87 ++++++++++++++++++++++++ test/e2e/framework/dashboard.go | 1 + test/e2e/gatewayapi/httproute.go | 86 ++++++++++++++++++++++++ test/e2e/ingress/ingress.go | 112 +++++++++++++++++++++++++++++++ 7 files changed, 300 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index c96681171..170cd261e 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,4 @@ api7-ingress-controller-conformance-report.yaml *.mdx .cursor/ - +.env diff --git a/Makefile b/Makefile index da8a844b3..a24493abe 100644 --- a/Makefile +++ b/Makefile @@ -140,6 +140,15 @@ kind-load-images: pull-infra-images kind-load-ingress-image @kind load docker-image kennethreitz/httpbin:latest --name $(KIND_NAME) @kind load docker-image jmalloc/echo-server:latest --name $(KIND_NAME) +.PHONY: kind-load-gateway-image +kind-load-gateway-image: + @kind load docker-image hkccr.ccs.tencentyun.com/api7-dev/api7-ee-3-gateway:dev --name $(KIND_NAME) + +.PHONY: kind-load-dashboard-images +kind-load-dashboard-images: + @kind load docker-image hkccr.ccs.tencentyun.com/api7-dev/api7-ee-dp-manager:$(DASHBOARD_VERSION) --name $(KIND_NAME) + @kind load docker-image hkccr.ccs.tencentyun.com/api7-dev/api7-ee-3-integrated:$(DASHBOARD_VERSION) --name $(KIND_NAME) + .PHONY: kind-load-ingress-image kind-load-ingress-image: @kind load docker-image $(IMG) --name $(KIND_NAME) diff --git a/internal/provider/adc/adc.go b/internal/provider/adc/adc.go index 2556004ba..c4a6de39c 100644 --- a/internal/provider/adc/adc.go +++ b/internal/provider/adc/adc.go @@ -32,10 +32,7 @@ type adcConfig struct { type adcClient struct { sync.Mutex - translator *translator.Translator - ServerAddr string - Token string - GatewayGroup string + translator *translator.Translator // gateway/ingressclass -> adcConfig configs map[provider.ResourceKind]adcConfig // httproute/consumer/ingress/gateway -> gateway/ingressclass @@ -164,6 +161,7 @@ func (d *adcClient) Delete(ctx context.Context, obj client.Object) error { } configs := d.getConfigs(rk) + defer d.deleteConfigs(rk) err := d.sync(ctx, Task{ Name: obj.GetName(), @@ -175,7 +173,6 @@ func (d *adcClient) Delete(ctx context.Context, obj client.Object) error { return err } - d.deleteConfigs(rk) return nil } @@ -233,14 +230,8 @@ func (d *adcClient) execADC(ctx context.Context, config adcConfig, args []string ctxWithTimeout, cancel := context.WithTimeout(ctx, d.syncTimeout) defer cancel() // todo: use adc config - serverAddr := d.ServerAddr - if config.ServerAddr != "" { - serverAddr = config.ServerAddr - } - token := d.Token - if config.Token != "" { - token = config.Token - } + serverAddr := config.ServerAddr + token := config.Token adcEnv := []string{ "ADC_EXPERIMENTAL_FEATURE_FLAGS=remote-state-file,parallel-backend-request", diff --git a/test/e2e/crds/consumer.go b/test/e2e/crds/consumer.go index 4d49af9fd..8c86f159b 100644 --- a/test/e2e/crds/consumer.go +++ b/test/e2e/crds/consumer.go @@ -1,11 +1,13 @@ package gatewayapi import ( + "fmt" "time" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "github.com/api7/api7-ingress-controller/test/e2e/framework" "github.com/api7/api7-ingress-controller/test/e2e/scaffold" ) @@ -376,4 +378,89 @@ spec: Status(401) }) }) + + Context("Consumer with GatewayProxy Update", func() { + var additionalGatewayGroupID string + + var defaultCredential = ` +apiVersion: apisix.apache.org/v1alpha1 +kind: Consumer +metadata: + name: consumer-sample +spec: + gatewayRef: + name: api7ee + credentials: + - type: basic-auth + name: basic-auth-sample + config: + username: sample-user + password: sample-password +` + var updatedGatewayProxy = ` +apiVersion: apisix.apache.org/v1alpha1 +kind: GatewayProxy +metadata: + name: api7-proxy-config +spec: + provider: + type: ControlPlane + controlPlane: + endpoints: + - %s + auth: + type: AdminKey + adminKey: + value: "%s" +` + + BeforeEach(func() { + s.ApplyDefaultGatewayResource(defaultGatewayProxy, defaultGatewayClass, defaultGateway, defaultHTTPRoute) + }) + + It("Should sync consumer when GatewayProxy is updated", func() { + s.ResourceApplied("Consumer", "consumer-sample", defaultCredential, 1) + + // verify basic-auth works + s.NewAPISIXClient(). + GET("/get"). + WithBasicAuth("sample-user", "sample-password"). + WithHost("httpbin.org"). + Expect(). + Status(200) + + By("create additional gateway group to get new admin key") + var err error + additionalGatewayGroupID, _, err = s.CreateAdditionalGatewayGroup("gateway-proxy-update") + Expect(err).NotTo(HaveOccurred(), "creating additional gateway group") + + resources, exists := s.GetAdditionalGatewayGroup(additionalGatewayGroupID) + Expect(exists).To(BeTrue(), "additional gateway group should exist") + + client, err := s.NewAPISIXClientForGatewayGroup(additionalGatewayGroupID) + Expect(err).NotTo(HaveOccurred(), "creating APISIX client for additional gateway group") + + By("Consumer not found for additional gateway group") + client. + GET("/get"). + WithBasicAuth("sample-user", "sample-password"). + WithHost("httpbin.org"). + Expect(). + Status(404) + + By("update GatewayProxy with new admin key") + updatedProxy := fmt.Sprintf(updatedGatewayProxy, framework.DashboardTLSEndpoint, resources.AdminAPIKey) + err = s.CreateResourceFromString(updatedProxy) + Expect(err).NotTo(HaveOccurred(), "updating GatewayProxy") + time.Sleep(30 * time.Second) + + By("verify Consumer works for additional gateway group") + client. + GET("/get"). + WithBasicAuth("sample-user", "sample-password"). + WithHost("httpbin.org"). + Expect(). + Status(200) + }) + }) }) diff --git a/test/e2e/framework/dashboard.go b/test/e2e/framework/dashboard.go index 395d30592..2d0cf22e7 100644 --- a/test/e2e/framework/dashboard.go +++ b/test/e2e/framework/dashboard.go @@ -367,6 +367,7 @@ func (f *Framework) GetDataplaneCertificates(gatewayGroupID string) *v1.Dataplan POST("/api/gateway_groups/"+gatewayGroupID+"/dp_client_certificates"). WithBasicAuth("admin", "admin"). WithHeader("Content-Type", "application/json"). + WithBytes([]byte(`{}`)). Expect() f.Logger.Logf(f.GinkgoT, "dataplane certificates issuer response: %s", respExp.Body().Raw()) diff --git a/test/e2e/gatewayapi/httproute.go b/test/e2e/gatewayapi/httproute.go index 5838be81b..54036610a 100644 --- a/test/e2e/gatewayapi/httproute.go +++ b/test/e2e/gatewayapi/httproute.go @@ -1394,6 +1394,92 @@ spec: }) }) + Context("HTTPRoute with GatewayProxy Update", func() { + var additionalGatewayGroupID string + + var exactRouteByGet = ` +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: httpbin +spec: + parentRefs: + - name: api7ee + hostnames: + - httpbin.example + rules: + - matches: + - path: + type: Exact + value: /get + backendRefs: + - name: httpbin-service-e2e-test + port: 80 +` + + var updatedGatewayProxy = ` +apiVersion: apisix.apache.org/v1alpha1 +kind: GatewayProxy +metadata: + name: api7-proxy-config +spec: + provider: + type: ControlPlane + controlPlane: + endpoints: + - %s + auth: + type: AdminKey + adminKey: + value: "%s" +` + + BeforeEach(beforeEachHTTP) + + It("Should sync HTTPRoute when GatewayProxy is updated", func() { + By("create HTTPRoute") + ResourceApplied("HTTPRoute", "httpbin", exactRouteByGet, 1) + + By("verify HTTPRoute works") + s.NewAPISIXClient(). + GET("/get"). + WithHost("httpbin.example"). + Expect(). + Status(200) + + By("create additional gateway group to get new admin key") + var err error + additionalGatewayGroupID, _, err = s.CreateAdditionalGatewayGroup("gateway-proxy-update") + Expect(err).NotTo(HaveOccurred(), "creating additional gateway group") + + resources, exists := s.GetAdditionalGatewayGroup(additionalGatewayGroupID) + Expect(exists).To(BeTrue(), "additional gateway group should exist") + + client, err := s.NewAPISIXClientForGatewayGroup(additionalGatewayGroupID) + Expect(err).NotTo(HaveOccurred(), "creating APISIX client for additional gateway group") + + By("HTTPRoute not found for additional gateway group") + client. + GET("/get"). + WithHost("httpbin.example"). + Expect(). + Status(404) + + By("update GatewayProxy with new admin key") + updatedProxy := fmt.Sprintf(updatedGatewayProxy, framework.DashboardTLSEndpoint, resources.AdminAPIKey) + err = s.CreateResourceFromString(updatedProxy) + Expect(err).NotTo(HaveOccurred(), "updating GatewayProxy") + time.Sleep(5 * time.Second) + + By("verify HTTPRoute works for additional gateway group") + client. + GET("/get"). + WithHost("httpbin.example"). + Expect(). + Status(200) + }) + }) + /* Context("HTTPRoute Status Updated", func() { }) diff --git a/test/e2e/ingress/ingress.go b/test/e2e/ingress/ingress.go index 0e810b4da..92c4a4a7a 100644 --- a/test/e2e/ingress/ingress.go +++ b/test/e2e/ingress/ingress.go @@ -638,4 +638,116 @@ spec: WithTimeout(8 * time.Second).ProbeEvery(time.Second).Should(Equal(http.StatusOK)) }) }) + + Context("Ingress with GatewayProxy Update", func() { + var additionalGatewayGroupID string + + var ingressClass = ` +apiVersion: networking.k8s.io/v1 +kind: IngressClass +metadata: + name: api7-ingress-class +spec: + controller: "apisix.apache.org/api7-ingress-controller" + parameters: + apiGroup: "apisix.apache.org" + kind: "GatewayProxy" + name: "api7-proxy-config" + namespace: "default" + scope: "Namespace" +` + var ingress = ` +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: api7-ingress +spec: + ingressClassName: api7-ingress-class + rules: + - host: ingress.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: httpbin-service-e2e-test + port: + number: 80 +` + var updatedGatewayProxy = ` +apiVersion: apisix.apache.org/v1alpha1 +kind: GatewayProxy +metadata: + name: api7-proxy-config + namespace: default +spec: + provider: + type: ControlPlane + controlPlane: + endpoints: + - %s + auth: + type: AdminKey + adminKey: + value: "%s" +` + + BeforeEach(func() { + By("create GatewayProxy") + gatewayProxy := fmt.Sprintf(gatewayProxyYaml, framework.DashboardTLSEndpoint, s.AdminKey()) + err := s.CreateResourceFromStringWithNamespace(gatewayProxy, "default") + Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy") + time.Sleep(5 * time.Second) + + By("create IngressClass") + err = s.CreateResourceFromStringWithNamespace(ingressClass, "") + Expect(err).NotTo(HaveOccurred(), "creating IngressClass") + time.Sleep(5 * time.Second) + }) + + It("Should sync Ingress when GatewayProxy is updated", func() { + By("create Ingress") + err := s.CreateResourceFromString(ingress) + Expect(err).NotTo(HaveOccurred(), "creating Ingress") + time.Sleep(5 * time.Second) + + By("verify Ingress works") + s.NewAPISIXClient(). + GET("/get"). + WithHost("ingress.example.com"). + Expect(). + Status(200) + + By("create additional gateway group to get new admin key") + additionalGatewayGroupID, _, err = s.CreateAdditionalGatewayGroup("gateway-proxy-update") + Expect(err).NotTo(HaveOccurred(), "creating additional gateway group") + + client, err := s.NewAPISIXClientForGatewayGroup(additionalGatewayGroupID) + Expect(err).NotTo(HaveOccurred(), "creating APISIX client for additional gateway group") + + By("Ingress not found for additional gateway group") + client. + GET("/get"). + WithHost("ingress.example.com"). + Expect(). + Status(404) + + resources, exists := s.GetAdditionalGatewayGroup(additionalGatewayGroupID) + Expect(exists).To(BeTrue(), "additional gateway group should exist") + + By("update GatewayProxy with new admin key") + updatedProxy := fmt.Sprintf(updatedGatewayProxy, framework.DashboardTLSEndpoint, resources.AdminAPIKey) + err = s.CreateResourceFromStringWithNamespace(updatedProxy, "default") + Expect(err).NotTo(HaveOccurred(), "updating GatewayProxy") + time.Sleep(5 * time.Second) + + By("verify Ingress works for additional gateway group") + client. + GET("/get"). + WithHost("ingress.example.com"). + Expect(). + Status(200) + }) + }) }) From 96bf53cdbe6eb4b8aa30c95aa4b8b1e2d3caa446 Mon Sep 17 00:00:00 2001 From: ashing Date: Thu, 24 Apr 2025 19:07:21 +0800 Subject: [PATCH 3/6] fix: r Signed-off-by: ashing --- test/e2e/crds/consumer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/crds/consumer.go b/test/e2e/crds/consumer.go index 8c86f159b..2681b5d9c 100644 --- a/test/e2e/crds/consumer.go +++ b/test/e2e/crds/consumer.go @@ -452,7 +452,7 @@ spec: updatedProxy := fmt.Sprintf(updatedGatewayProxy, framework.DashboardTLSEndpoint, resources.AdminAPIKey) err = s.CreateResourceFromString(updatedProxy) Expect(err).NotTo(HaveOccurred(), "updating GatewayProxy") - time.Sleep(30 * time.Second) + time.Sleep(5 * time.Second) By("verify Consumer works for additional gateway group") client. From 47446fbd9ab99af51058b7a6e414d4445245d7ba Mon Sep 17 00:00:00 2001 From: ashing Date: Thu, 24 Apr 2025 22:10:48 +0800 Subject: [PATCH 4/6] fix: r Signed-off-by: ashing --- config/samples/config.yaml | 4 ++-- internal/controller/config/config.go | 4 ++-- internal/controller/config/types.go | 6 +++--- internal/provider/adc/adc.go | 5 +++++ 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/config/samples/config.yaml b/config/samples/config.yaml index 52990cfad..e3c6c1dee 100644 --- a/config/samples/config.yaml +++ b/config/samples/config.yaml @@ -7,10 +7,10 @@ controller_name: apisix.apache.org/api7-ingress-controller # The controller nam leader_election_id: "api7-ingress-controller-leader" # The leader election ID for the API7 Ingress Controller. # The default value is "api7-ingress-controller-leader". leader_election: - lease_duration: 15s # lease_duration is the duration that non-leader candidates will wait + lease_duration: 30s # lease_duration is the duration that non-leader candidates will wait # after observing a leadership renewal until attempting to acquire leadership of a # leader election. - renew_deadline: 10s # renew_deadline is the time in seconds that the acting controller + renew_deadline: 20s # renew_deadline is the time in seconds that the acting controller # will retry refreshing leadership before giving up. retry_period: 2s # retry_period is the time in seconds that the acting controller # will wait between tries of actions with the controller. diff --git a/internal/controller/config/config.go b/internal/controller/config/config.go index d41ddb1e9..ba5b5320b 100644 --- a/internal/controller/config/config.go +++ b/internal/controller/config/config.go @@ -37,8 +37,8 @@ func NewDefaultConfig() *Config { func NewLeaderElection() *LeaderElection { return &LeaderElection{ - LeaseDuration: types.TimeDuration{Duration: 15 * time.Second}, - RenewDeadline: types.TimeDuration{Duration: 10 * time.Second}, + LeaseDuration: types.TimeDuration{Duration: 30 * time.Second}, + RenewDeadline: types.TimeDuration{Duration: 20 * time.Second}, RetryPeriod: types.TimeDuration{Duration: 2 * time.Second}, Disable: false, } diff --git a/internal/controller/config/types.go b/internal/controller/config/types.go index a4d8db3f5..543d16c86 100644 --- a/internal/controller/config/types.go +++ b/internal/controller/config/types.go @@ -50,8 +50,8 @@ type ControlPlaneConfig struct { } type LeaderElection struct { - LeaseDuration types.TimeDuration `json:"leaseDuration,omitempty" yaml:"leaseDuration,omitempty"` - RenewDeadline types.TimeDuration `json:"renewDeadline,omitempty" yaml:"renewDeadline,omitempty"` - RetryPeriod types.TimeDuration `json:"retryPeriod,omitempty" yaml:"retryPeriod,omitempty"` + LeaseDuration types.TimeDuration `json:"lease_duration,omitempty" yaml:"lease_duration,omitempty"` + RenewDeadline types.TimeDuration `json:"renew_deadline,omitempty" yaml:"renew_deadline,omitempty"` + RetryPeriod types.TimeDuration `json:"retry_period,omitempty" yaml:"retry_period,omitempty"` Disable bool `json:"disable,omitempty" yaml:"disable,omitempty"` } diff --git a/internal/provider/adc/adc.go b/internal/provider/adc/adc.go index c4a6de39c..67acc5451 100644 --- a/internal/provider/adc/adc.go +++ b/internal/provider/adc/adc.go @@ -32,6 +32,8 @@ type adcConfig struct { type adcClient struct { sync.Mutex + execLock sync.Mutex + translator *translator.Translator // gateway/ingressclass -> adcConfig configs map[provider.ResourceKind]adcConfig @@ -227,6 +229,9 @@ func (d *adcClient) sync(ctx context.Context, task Task) error { } func (d *adcClient) execADC(ctx context.Context, config adcConfig, args []string) error { + d.execLock.Lock() + defer d.execLock.Unlock() + ctxWithTimeout, cancel := context.WithTimeout(ctx, d.syncTimeout) defer cancel() // todo: use adc config From 4fdafef973b9233f7692602f3239eaf28f8c5e68 Mon Sep 17 00:00:00 2001 From: ashing Date: Fri, 25 Apr 2025 01:53:57 +0800 Subject: [PATCH 5/6] fix: httpbinorg Signed-off-by: ashing --- test/e2e/gatewayapi/httproute.go | 4 ++-- test/e2e/ingress/ingress.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/gatewayapi/httproute.go b/test/e2e/gatewayapi/httproute.go index 54036610a..7bce28a45 100644 --- a/test/e2e/gatewayapi/httproute.go +++ b/test/e2e/gatewayapi/httproute.go @@ -372,7 +372,7 @@ metadata: name: httpbin-external-domain spec: type: ExternalName - externalName: httpbin.org + externalName: postman-echo.com --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute @@ -465,7 +465,7 @@ spec: Status(404) }) - It("Proxy External Service", func() { + FIt("Proxy External Service", func() { By("create HTTPRoute") ResourceApplied("HTTPRoute", "httpbin", httprouteWithExternalName, 1) diff --git a/test/e2e/ingress/ingress.go b/test/e2e/ingress/ingress.go index 92c4a4a7a..029954ad3 100644 --- a/test/e2e/ingress/ingress.go +++ b/test/e2e/ingress/ingress.go @@ -165,7 +165,7 @@ metadata: name: httpbin-external-domain spec: type: ExternalName - externalName: httpbin.org + externalName: postman-echo.com --- apiVersion: networking.k8s.io/v1 kind: Ingress From 14efe1948eb2767ba4c047cf41b98b9172731e06 Mon Sep 17 00:00:00 2001 From: ashing Date: Fri, 25 Apr 2025 01:56:10 +0800 Subject: [PATCH 6/6] fix: r Signed-off-by: ashing --- test/e2e/gatewayapi/httproute.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/gatewayapi/httproute.go b/test/e2e/gatewayapi/httproute.go index 7bce28a45..78c06f1db 100644 --- a/test/e2e/gatewayapi/httproute.go +++ b/test/e2e/gatewayapi/httproute.go @@ -465,7 +465,7 @@ spec: Status(404) }) - FIt("Proxy External Service", func() { + It("Proxy External Service", func() { By("create HTTPRoute") ResourceApplied("HTTPRoute", "httpbin", httprouteWithExternalName, 1)