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 <[email protected]>
AuthorDate: Thu Jan 8 18:21:29 2026 +0800

    fix: modify upstream name generation method (#2694)
    
    Signed-off-by: Ashing Zheng <[email protected]>
    (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),
+                       })
+               })
+       })
 })

Reply via email to