This is an automated email from the ASF dual-hosted git repository. nic443 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/apisix-ingress-controller.git
The following commit(s) were added to refs/heads/master by this push: new 59ded942 fix: Add provider endpoints to translate context (#2442) 59ded942 is described below commit 59ded9429670fab36b4cfba6bc4ba27e4d660670 Author: 悟空 <rainchan...@163.com> AuthorDate: Wed Jul 2 21:31:36 2025 +0800 fix: Add provider endpoints to translate context (#2442) --- api/v1alpha1/gatewayproxy_types.go | 6 +- .../bases/apisix.apache.org_gatewayproxies.yaml | 3 +- internal/controller/gatewayclass_congroller.go | 3 - internal/controller/ingressclass_controller.go | 10 ++ internal/controller/utils.go | 153 ++++++++++++++------- internal/provider/adc/config.go | 18 ++- test/e2e/gatewayapi/httproute.go | 30 +++- 7 files changed, 154 insertions(+), 69 deletions(-) diff --git a/api/v1alpha1/gatewayproxy_types.go b/api/v1alpha1/gatewayproxy_types.go index 66760cdb..bf8b802a 100644 --- a/api/v1alpha1/gatewayproxy_types.go +++ b/api/v1alpha1/gatewayproxy_types.go @@ -22,9 +22,6 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - // GatewayProxySpec defines the desired state of GatewayProxy. type GatewayProxySpec struct { // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster @@ -116,9 +113,10 @@ type ControlPlaneAuth struct { } // ControlPlaneProvider defines the configuration for control plane provider. +// +kubebuilder:validation:XValidation:rule="has(self.endpoints) != has(self.service)" type ControlPlaneProvider struct { // Endpoints specifies the list of control plane endpoints. - // +kubebuilder:validation:Required + // +kubebuilder:validation:Optional // +kubebuilder:validation:MinItems=1 Endpoints []string `json:"endpoints"` diff --git a/config/crd/bases/apisix.apache.org_gatewayproxies.yaml b/config/crd/bases/apisix.apache.org_gatewayproxies.yaml index df91df23..cd5f42c0 100644 --- a/config/crd/bases/apisix.apache.org_gatewayproxies.yaml +++ b/config/crd/bases/apisix.apache.org_gatewayproxies.yaml @@ -137,8 +137,9 @@ spec: type: boolean required: - auth - - endpoints type: object + x-kubernetes-validations: + - rule: has(self.endpoints) != has(self.service) type: description: Type specifies the type of provider. Can only be `ControlPlane`. diff --git a/internal/controller/gatewayclass_congroller.go b/internal/controller/gatewayclass_congroller.go index 128e5c18..ec3a7d92 100644 --- a/internal/controller/gatewayclass_congroller.go +++ b/internal/controller/gatewayclass_congroller.go @@ -43,9 +43,6 @@ const ( FinalizerGatewayClassProtection = "apisix.apache.org/gc-protection" ) -// +kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=gatewayclasses,verbs=get;list;watch;update -// +kubebuilder:rbac:groups=gateway.networking.k8s.io,resources=gatewayclasses/status,verbs=get;update - // GatewayClassReconciler reconciles a GatewayClass object. type GatewayClassReconciler struct { //nolint:revive client.Client diff --git a/internal/controller/ingressclass_controller.go b/internal/controller/ingressclass_controller.go index c3442d52..0d71bd54 100644 --- a/internal/controller/ingressclass_controller.go +++ b/internal/controller/ingressclass_controller.go @@ -27,6 +27,7 @@ import ( networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" @@ -229,6 +230,15 @@ func (r *IngressClassReconciler) processInfrastructure(tctx *provider.TranslateC } } + if service := gatewayProxy.Spec.Provider.ControlPlane.Service; service != nil { + if err := addProviderEndpointsToTranslateContext(tctx, r.Client, 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") diff --git a/internal/controller/utils.go b/internal/controller/utils.go index a0c3ebb0..d1049046 100644 --- a/internal/controller/utils.go +++ b/internal/controller/utils.go @@ -33,6 +33,7 @@ import ( "github.com/samber/lo" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" + discoveryv1 "k8s.io/api/discovery/v1" networkingv1 "k8s.io/api/networking/v1" "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -921,34 +922,44 @@ func ProcessGatewayProxy(r client.Client, tctx *provider.TranslateContext, gatew tctx.ResourceParentRefs[rk] = append(tctx.ResourceParentRefs[rk], gatewayKind) // Process provider secrets if provider exists - if gatewayProxy.Spec.Provider != nil && gatewayProxy.Spec.Provider.Type == v1alpha1.ProviderTypeControlPlane { - if gatewayProxy.Spec.Provider.ControlPlane != nil && - gatewayProxy.Spec.Provider.ControlPlane.Auth.Type == v1alpha1.AuthTypeAdminKey && - gatewayProxy.Spec.Provider.ControlPlane.Auth.AdminKey != nil && - gatewayProxy.Spec.Provider.ControlPlane.Auth.AdminKey.ValueFrom != nil && - gatewayProxy.Spec.Provider.ControlPlane.Auth.AdminKey.ValueFrom.SecretKeyRef != nil { - - secretRef := gatewayProxy.Spec.Provider.ControlPlane.Auth.AdminKey.ValueFrom.SecretKeyRef - secret := &corev1.Secret{} - if err := r.Get(context.Background(), client.ObjectKey{ - Namespace: ns, - Name: secretRef.Name, - }, secret); err != nil { - log.Error(err, "failed to get secret for GatewayProxy provider", - "namespace", ns, - "name", secretRef.Name) - return err - } + if prov := gatewayProxy.Spec.Provider; prov != nil && prov.Type == v1alpha1.ProviderTypeControlPlane { + if cp := prov.ControlPlane; cp != nil { + if cp.Auth.Type == v1alpha1.AuthTypeAdminKey && + cp.Auth.AdminKey != nil && + cp.Auth.AdminKey.ValueFrom != nil && + cp.Auth.AdminKey.ValueFrom.SecretKeyRef != nil { + + secretRef := cp.Auth.AdminKey.ValueFrom.SecretKeyRef + secret := &corev1.Secret{} + if err := r.Get(context.Background(), client.ObjectKey{ + Namespace: ns, + Name: secretRef.Name, + }, secret); err != nil { + log.Error(err, "failed to get secret for GatewayProxy provider", + "namespace", ns, + "name", secretRef.Name) + return err + } - log.Info("found secret for GatewayProxy provider", - "gateway", gateway.Name, - "gatewayproxy", gatewayProxy.Name, - "secret", secretRef.Name) + log.Info("found secret for GatewayProxy provider", + "gateway", gateway.Name, + "gatewayproxy", gatewayProxy.Name, + "secret", secretRef.Name) - tctx.Secrets[k8stypes.NamespacedName{ - Namespace: ns, - Name: secretRef.Name, - }] = secret + tctx.Secrets[k8stypes.NamespacedName{ + Namespace: ns, + Name: secretRef.Name, + }] = secret + } + + if cp.Service != nil { + if err := addProviderEndpointsToTranslateContext(tctx, r, k8stypes.NamespacedName{ + Namespace: gatewayProxy.GetNamespace(), + Name: cp.Service.Name, + }); err != nil { + return err + } + } } } } @@ -1340,33 +1351,45 @@ func ProcessIngressClassParameters(tctx *provider.TranslateContext, c client.Cli // check if the provider field references a secret if gatewayProxy.Spec.Provider != nil && gatewayProxy.Spec.Provider.Type == v1alpha1.ProviderTypeControlPlane { - if gatewayProxy.Spec.Provider.ControlPlane != nil && - gatewayProxy.Spec.Provider.ControlPlane.Auth.Type == v1alpha1.AuthTypeAdminKey && - gatewayProxy.Spec.Provider.ControlPlane.Auth.AdminKey != nil && - gatewayProxy.Spec.Provider.ControlPlane.Auth.AdminKey.ValueFrom != nil && - gatewayProxy.Spec.Provider.ControlPlane.Auth.AdminKey.ValueFrom.SecretKeyRef != nil { - - secretRef := gatewayProxy.Spec.Provider.ControlPlane.Auth.AdminKey.ValueFrom.SecretKeyRef - secret := &corev1.Secret{} - if err := c.Get(tctx, client.ObjectKey{ - Namespace: ns, - Name: secretRef.Name, - }, secret); err != nil { - log.Error(err, "failed to get secret for GatewayProxy provider", - "namespace", ns, - "name", secretRef.Name) - return err - } + if cp := gatewayProxy.Spec.Provider.ControlPlane; cp != nil { + // process control plane provider auth + if cp.Auth.Type == v1alpha1.AuthTypeAdminKey && + cp.Auth.AdminKey != nil && + cp.Auth.AdminKey.ValueFrom != nil && + cp.Auth.AdminKey.ValueFrom.SecretKeyRef != nil { + + secretRef := cp.Auth.AdminKey.ValueFrom.SecretKeyRef + secret := &corev1.Secret{} + if err := c.Get(tctx, client.ObjectKey{ + Namespace: ns, + Name: secretRef.Name, + }, secret); err != nil { + log.Error(err, "failed to get secret for GatewayProxy provider", + "namespace", ns, + "name", secretRef.Name) + return err + } - log.Info("found secret for GatewayProxy provider", - "ingressClass", ingressClass.Name, - "gatewayproxy", gatewayProxy.Name, - "secret", secretRef.Name) + log.Info("found secret for GatewayProxy provider", + "ingressClass", ingressClass.Name, + "gatewayproxy", gatewayProxy.Name, + "secret", secretRef.Name) + + tctx.Secrets[k8stypes.NamespacedName{ + Namespace: ns, + Name: secretRef.Name, + }] = secret + } - tctx.Secrets[k8stypes.NamespacedName{ - Namespace: ns, - Name: secretRef.Name, - }] = secret + // process control plane provider service + if cp.Service != nil { + if err := addProviderEndpointsToTranslateContext(tctx, c, client.ObjectKey{ + Namespace: gatewayProxy.GetNamespace(), + Name: cp.Service.Name, + }); err != nil { + return err + } + } } } } @@ -1420,3 +1443,31 @@ func distinctRequests(requests []reconcile.Request) []reconcile.Request { } return distinctRequests } + +func addProviderEndpointsToTranslateContext(tctx *provider.TranslateContext, c client.Client, serviceNN k8stypes.NamespacedName) error { + log.Debugf("to process provider endpints by provider.service: %s", serviceNN) + var ( + service corev1.Service + ) + if err := c.Get(tctx, serviceNN, &service); err != nil { + log.Error(err, "failed to get service from GatewayProxy provider", "key", serviceNN) + return err + } + tctx.Services[serviceNN] = &service + + // get es + var ( + esList discoveryv1.EndpointSliceList + ) + if err := c.List(tctx, &esList, + client.InNamespace(serviceNN.Namespace), + client.MatchingLabels{ + discoveryv1.LabelServiceName: serviceNN.Name, + }); err != nil { + log.Error(err, "failed to get endpoints for GatewayProxy provider", "endpoints", serviceNN) + return err + } + tctx.EndpointSlices[serviceNN] = esList.Items + + return nil +} diff --git a/internal/provider/adc/config.go b/internal/provider/adc/config.go index 6e597b78..e20c46e4 100644 --- a/internal/provider/adc/config.go +++ b/internal/provider/adc/config.go @@ -18,11 +18,12 @@ package adc import ( - "errors" - "fmt" + "net" "slices" + "strconv" "github.com/api7/gopkg/pkg/log" + "github.com/pkg/errors" "go.uber.org/zap" k8stypes "k8s.io/apimachinery/pkg/types" "k8s.io/utils/ptr" @@ -30,7 +31,7 @@ import ( "github.com/apache/apisix-ingress-controller/api/v1alpha1" "github.com/apache/apisix-ingress-controller/internal/provider" - types "github.com/apache/apisix-ingress-controller/internal/types" + "github.com/apache/apisix-ingress-controller/internal/types" ) func (d *adcClient) getConfigsForGatewayProxy(tctx *provider.TranslateContext, gatewayProxy *v1alpha1.GatewayProxy) (*adcConfig, error) { @@ -86,7 +87,7 @@ func (d *adcClient) getConfigsForGatewayProxy(tctx *provider.TranslateContext, g } _, ok := tctx.Services[namespacedName] if !ok { - return nil, errors.New("no service found for service reference") + return nil, errors.Errorf("no service found for service reference: %s", namespacedName) } endpoint := tctx.EndpointSlices[namespacedName] if endpoint == nil { @@ -94,16 +95,19 @@ func (d *adcClient) getConfigsForGatewayProxy(tctx *provider.TranslateContext, g } upstreamNodes, err := d.translator.TranslateBackendRef(tctx, v1.BackendRef{ BackendObjectReference: v1.BackendObjectReference{ - Name: v1.ObjectName(provider.ControlPlane.Service.Name), - Port: ptr.To(v1.PortNumber(provider.ControlPlane.Service.Port)), + Name: v1.ObjectName(provider.ControlPlane.Service.Name), + Namespace: (*v1.Namespace)(&gatewayProxy.Namespace), + Port: ptr.To(v1.PortNumber(provider.ControlPlane.Service.Port)), }, }) if err != nil { return nil, err } for _, node := range upstreamNodes { - config.ServerAddrs = append(config.ServerAddrs, fmt.Sprintf("http://%s:%d", node.Host, node.Port)) + config.ServerAddrs = append(config.ServerAddrs, "http://"+net.JoinHostPort(node.Host, strconv.Itoa(node.Port))) } + + log.Debugf("add server address to config.ServiceAddrs: %v", config.ServerAddrs) } return &config, nil diff --git a/test/e2e/gatewayapi/httproute.go b/test/e2e/gatewayapi/httproute.go index 5b9afd37..ae487e93 100644 --- a/test/e2e/gatewayapi/httproute.go +++ b/test/e2e/gatewayapi/httproute.go @@ -34,6 +34,7 @@ import ( "sigs.k8s.io/gateway-api/apis/v1alpha2" "github.com/apache/apisix-ingress-controller/api/v1alpha1" + "github.com/apache/apisix-ingress-controller/internal/provider/adc" "github.com/apache/apisix-ingress-controller/test/e2e/framework" "github.com/apache/apisix-ingress-controller/test/e2e/scaffold" ) @@ -41,7 +42,28 @@ import ( var _ = Describe("Test HTTPRoute", Label("networking.k8s.io", "httproute"), func() { s := scaffold.NewDefaultScaffold() - var gatewayProxyYaml = ` + getGatewayProxySpec := func(endpoint, adminKey string) string { + if framework.ProviderType == adc.BackendModeAPISIXStandalone { + var gatewayProxyYaml = ` +apiVersion: apisix.apache.org/v1alpha1 +kind: GatewayProxy +metadata: + name: apisix-proxy-config +spec: + provider: + type: ControlPlane + controlPlane: + service: + name: apisix-standalone + port: 9180 + auth: + type: AdminKey + adminKey: + value: "%s" +` + return fmt.Sprintf(gatewayProxyYaml, adminKey) + } + var gatewayProxyYaml = ` apiVersion: apisix.apache.org/v1alpha1 kind: GatewayProxy metadata: @@ -57,6 +79,8 @@ spec: adminKey: value: "%s" ` + return fmt.Sprintf(gatewayProxyYaml, endpoint, adminKey) + } var gatewayClassYaml = ` apiVersion: gateway.networking.k8s.io/v1 @@ -129,7 +153,7 @@ spec: var beforeEachHTTP = func() { By("create GatewayProxy") - gatewayProxy := fmt.Sprintf(gatewayProxyYaml, s.Deployer.GetAdminEndpoint(), s.AdminKey()) + gatewayProxy := getGatewayProxySpec(s.Deployer.GetAdminEndpoint(), s.AdminKey()) err := s.CreateResourceFromString(gatewayProxy) Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy") time.Sleep(5 * time.Second) @@ -160,7 +184,7 @@ spec: var beforeEachHTTPS = func() { By("create GatewayProxy") - gatewayProxy := fmt.Sprintf(gatewayProxyYaml, s.Deployer.GetAdminEndpoint(), s.AdminKey()) + gatewayProxy := getGatewayProxySpec(s.Deployer.GetAdminEndpoint(), s.AdminKey()) err := s.CreateResourceFromString(gatewayProxy) Expect(err).NotTo(HaveOccurred(), "creating GatewayProxy") time.Sleep(5 * time.Second)