You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ro...@apache.org on 2026/01/12 08:32:36 UTC

(apisix-ingress-controller) 05/08: fix: modify upstream name generation method (#2694)

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 c6e00d7d62a9519ed5156d149a94cab367eb984e
Author: Ashing Zheng <ax...@gmail.com>
AuthorDate: Thu Jan 8 18:21:29 2026 +0800

    fix: modify upstream name generation method (#2694)
    
    Signed-off-by: Ashing Zheng <ax...@gmail.com>
    (cherry picked from commit 80585882b8460619bd123f85efa61d0465b1b218)
---
 api/adc/types.go                       | 30 +++-----------
 internal/adc/translator/apisixroute.go |  8 ++--
 test/e2e/crds/v2/route.go              | 71 ++++++++++++++++++++++++++++++++++
 3 files changed, 81 insertions(+), 28 deletions(-)

diff --git a/api/adc/types.go b/api/adc/types.go
index f4557450..b1738bf2 100644
--- a/api/adc/types.go
+++ b/api/adc/types.go
@@ -27,7 +27,6 @@ import (
 	"time"
 
 	"github.com/incubator4/go-resty-expr/expr"
-	"k8s.io/apimachinery/pkg/util/intstr"
 )
 
 const (
@@ -816,22 +815,11 @@ var (
 	}
 )
 
-// ComposeUpstreamName uses namespace, name, subset (optional), port, resolveGranularity info to compose
+// ComposeUpstreamName uses namespace, name, ruleIndex, backendIndex, serviceName info to compose
 // the upstream name.
-// the resolveGranularity is not composited in the upstream name when it is endpoint.
-// ref: https://github.com/apache/apisix-ingress-controller/blob/10059afe3e84b693cc61e6df7a0040890a9d16eb/pkg/types/apisix/v1/types.go#L595-L598
-func ComposeUpstreamName(namespace, name, subset string, port intstr.IntOrString, resolveGranularity string) string {
-	pstr := port.String()
-	// FIXME Use sync.Pool to reuse this buffer if the upstream
-	// name composing code path is hot.
+func ComposeUpstreamName(namespace, name, ruleIndex, backendIndex string) string {
 	var p []byte
-	plen := len(namespace) + len(name) + len(pstr) + 2
-	if subset != "" {
-		plen = plen + len(subset) + 1
-	}
-	if resolveGranularity == ResolveGranularity.Service {
-		plen = plen + len(resolveGranularity) + 1
-	}
+	plen := len(namespace) + len(name) + len(ruleIndex) + len(backendIndex) + 3
 
 	p = make([]byte, 0, plen)
 	buf := bytes.NewBuffer(p)
@@ -839,15 +827,9 @@ func ComposeUpstreamName(namespace, name, subset string, port intstr.IntOrString
 	buf.WriteByte('_')
 	buf.WriteString(name)
 	buf.WriteByte('_')
-	if subset != "" {
-		buf.WriteString(subset)
-		buf.WriteByte('_')
-	}
-	buf.WriteString(pstr)
-	if resolveGranularity == ResolveGranularity.Service {
-		buf.WriteByte('_')
-		buf.WriteString(resolveGranularity)
-	}
+	buf.WriteString(ruleIndex)
+	buf.WriteByte('_')
+	buf.WriteString(backendIndex)
 
 	return buf.String()
 }
diff --git a/internal/adc/translator/apisixroute.go b/internal/adc/translator/apisixroute.go
index f5a509e1..575d26e4 100644
--- a/internal/adc/translator/apisixroute.go
+++ b/internal/adc/translator/apisixroute.go
@@ -72,7 +72,7 @@ func (t *Translator) translateHTTPRule(tctx *provider.TranslateContext, ar *apiv
 
 	var enableWebsocket *bool
 	service := t.buildService(ar, rule, ruleIndex)
-	t.buildUpstream(tctx, service, ar, rule, &enableWebsocket)
+	t.buildUpstream(tctx, service, ar, rule, ruleIndex, &enableWebsocket)
 	t.buildRoute(ar, service, rule, plugins, timeout, vars, &enableWebsocket)
 	return service, nil
 }
@@ -205,13 +205,13 @@ func (t *Translator) buildRoute(ar *apiv2.ApisixRoute, service *adc.Service, rul
 	service.Routes = []*adc.Route{route}
 }
 
-func (t *Translator) buildUpstream(tctx *provider.TranslateContext, service *adc.Service, ar *apiv2.ApisixRoute, rule apiv2.ApisixRouteHTTP, enableWebsocket **bool) {
+func (t *Translator) buildUpstream(tctx *provider.TranslateContext, service *adc.Service, ar *apiv2.ApisixRoute, rule apiv2.ApisixRouteHTTP, ruleIndex int, enableWebsocket **bool) {
 	var (
 		upstreams         = make([]*adc.Upstream, 0)
 		weightedUpstreams = make([]adc.TrafficSplitConfigRuleWeightedUpstream, 0)
 	)
 
-	for _, backend := range rule.Backends {
+	for backendIndex, backend := range rule.Backends {
 		// try to get the apisixupstream with the same name as the backend service to be upstream config.
 		// err is ignored because it does not care about the externalNodes of the apisixupstream.
 		upstream, err := t.translateApisixRouteHTTPBackend(tctx, ar, backend, enableWebsocket)
@@ -220,7 +220,7 @@ func (t *Translator) buildUpstream(tctx *provider.TranslateContext, service *adc
 			continue
 		}
 
-		upstreamName := adc.ComposeUpstreamName(ar.Namespace, backend.ServiceName, backend.Subset, backend.ServicePort, backend.ResolveGranularity)
+		upstreamName := adc.ComposeUpstreamName(ar.Namespace, ar.Name, fmt.Sprintf("%d", ruleIndex), fmt.Sprintf("%d", backendIndex))
 		upstream.Name = upstreamName
 		upstream.ID = id.GenID(upstreamName)
 		upstreams = append(upstreams, upstream)
diff --git a/test/e2e/crds/v2/route.go b/test/e2e/crds/v2/route.go
index 67c6770f..a1a9edc6 100644
--- a/test/e2e/crds/v2/route.go
+++ b/test/e2e/crds/v2/route.go
@@ -2166,4 +2166,75 @@ spec:
 			Expect(string(msg)).To(Equal(testMessage), "message content verification")
 		})
 	})
+
+	Context("Test ApisixRoute with multiple backends", func() {
+		It("create ApisixRoute with multiple backends", func() {
+			var httpService = `
+apiVersion: v1
+kind: Service
+metadata:
+  name: httpbin-service-e2e-test2
+spec:
+  selector:
+    app: httpbin-deployment-e2e-test
+  ports:
+    - name: http
+      port: 80
+      protocol: TCP
+      targetPort: 80
+  type: ClusterIP
+`
+			err := s.CreateResourceFromString(httpService)
+			Expect(err).ShouldNot(HaveOccurred())
+			s.EnsureNumEndpointsReady(GinkgoT(), "httpbin-service-e2e-test2", 1)
+
+			const apisixRouteSpec = `
+apiVersion: apisix.apache.org/v2
+kind: ApisixRoute
+metadata:
+  name: httpbin
+spec:
+  ingressClassName: %s
+  http:
+    - name: get
+      match:
+        paths:
+          - /get
+      backends:
+        - serviceName: httpbin-service-e2e-test
+          servicePort: 80
+        - serviceName: httpbin-service-e2e-test2
+          servicePort: 80
+    - name: ip
+      match:
+        paths:
+          - /ip
+      backends:
+        - serviceName: httpbin-service-e2e-test
+          servicePort: 80
+        - serviceName: httpbin-service-e2e-test2
+          servicePort: 80
+`
+			By("apply ApisixRoute")
+			applier.MustApplyAPIv2(types.NamespacedName{Namespace: s.Namespace(), Name: "httpbin"},
+				&apiv2.ApisixRoute{}, fmt.Sprintf(apisixRouteSpec, s.Namespace()))
+
+			By("check upstreams")
+			upstreams, err := s.DefaultDataplaneResource().Upstream().List(context.Background())
+			Expect(err).ShouldNot(HaveOccurred())
+			Expect(upstreams).Should(HaveLen(4))
+
+			By("verify ApisixRoute works")
+			s.RequestAssert(&scaffold.RequestAssert{
+				Method: "GET",
+				Path:   "/get",
+				Check:  scaffold.WithExpectedStatus(http.StatusOK),
+			})
+			s.RequestAssert(&scaffold.RequestAssert{
+				Method: "GET",
+				Path:   "/ip",
+				Check:  scaffold.WithExpectedStatus(http.StatusOK),
+			})
+		})
+	})
 })