Skip to content

Commit 7f6cff4

Browse files
authored
fix: use upstream id instead of inline upstream in traffic-split plugin (#2546)
Signed-off-by: Ashing Zheng <[email protected]>
1 parent cb69f53 commit 7f6cff4

File tree

5 files changed

+121
-6
lines changed

5 files changed

+121
-6
lines changed

.github/workflows/apisix-e2e-test.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ concurrency:
3131
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
3232
cancel-in-progress: true
3333

34+
env:
35+
ADC_VERSION: dev
36+
3437
jobs:
3538
e2e-test:
3639
strategy:

api/adc/types.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ type Service struct {
168168
StreamRoutes []*StreamRoute `json:"stream_routes,omitempty" yaml:"stream_routes,omitempty"`
169169
StripPathPrefix *bool `json:"strip_path_prefix,omitempty" yaml:"strip_path_prefix,omitempty"`
170170
Upstream *Upstream `json:"upstream,omitempty" yaml:"upstream,omitempty"`
171+
Upstreams []*Upstream `json:"upstreams,omitempty" yaml:"upstreams,omitempty"`
171172
}
172173

173174
// +k8s:deepcopy-gen=true
@@ -761,3 +762,59 @@ func (c Config) MarshalJSON() ([]byte, error) {
761762
TlsVerify: c.TlsVerify,
762763
})
763764
}
765+
766+
var (
767+
ResolveGranularity = struct {
768+
Endpoint string
769+
Service string
770+
}{
771+
Endpoint: "endpoint",
772+
Service: "service",
773+
}
774+
)
775+
776+
// ComposeUpstreamName uses namespace, name, subset (optional), port, resolveGranularity info to compose
777+
// the upstream name.
778+
// the resolveGranularity is not composited in the upstream name when it is endpoint.
779+
// ref: https://github.com/apache/apisix-ingress-controller/blob/10059afe3e84b693cc61e6df7a0040890a9d16eb/pkg/types/apisix/v1/types.go#L595-L598
780+
func ComposeUpstreamName(namespace, name, subset string, port int32, resolveGranularity string) string {
781+
pstr := strconv.Itoa(int(port))
782+
// FIXME Use sync.Pool to reuse this buffer if the upstream
783+
// name composing code path is hot.
784+
var p []byte
785+
plen := len(namespace) + len(name) + len(pstr) + 2
786+
if subset != "" {
787+
plen = plen + len(subset) + 1
788+
}
789+
if resolveGranularity == ResolveGranularity.Service {
790+
plen = plen + len(resolveGranularity) + 1
791+
}
792+
793+
p = make([]byte, 0, plen)
794+
buf := bytes.NewBuffer(p)
795+
buf.WriteString(namespace)
796+
buf.WriteByte('_')
797+
buf.WriteString(name)
798+
buf.WriteByte('_')
799+
if subset != "" {
800+
buf.WriteString(subset)
801+
buf.WriteByte('_')
802+
}
803+
buf.WriteString(pstr)
804+
if resolveGranularity == ResolveGranularity.Service {
805+
buf.WriteByte('_')
806+
buf.WriteString(resolveGranularity)
807+
}
808+
809+
return buf.String()
810+
}
811+
812+
// ComposeExternalUpstreamName uses ApisixUpstream namespace, name to compose the upstream name.
813+
func ComposeExternalUpstreamName(namespace, name string) string {
814+
return namespace + "_" + name
815+
}
816+
817+
// ComposeUpstreamNameForBackendRef composes upstream name using kind, namespace, name and port.
818+
func ComposeUpstreamNameForBackendRef(kind, namespace, name string, port int32) string {
819+
return fmt.Sprintf("%s_%s_%s_%d", kind, namespace, name, port)
820+
}

api/adc/zz_generated.deepcopy.go

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/adc/translator/apisixroute.go

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,10 @@ func (t *Translator) buildUpstream(tctx *provider.TranslateContext, service *adc
226226
if backend.Weight != nil {
227227
upstream.Labels["meta_weight"] = strconv.FormatInt(int64(*backend.Weight), 10)
228228
}
229+
230+
upstreamName := adc.ComposeUpstreamName(ar.Namespace, backend.ServiceName, backend.Subset, int32(backend.ServicePort.IntValue()), backend.ResolveGranularity)
231+
upstream.Name = upstreamName
232+
upstream.ID = id.GenID(upstreamName)
229233
upstreams = append(upstreams, upstream)
230234
}
231235

@@ -248,6 +252,9 @@ func (t *Translator) buildUpstream(tctx *provider.TranslateContext, service *adc
248252
upstream.Labels["meta_weight"] = strconv.FormatInt(int64(*upstreamRef.Weight), 10)
249253
}
250254

255+
upstreamName := adc.ComposeExternalUpstreamName(upsNN.Namespace, upsNN.Name)
256+
upstream.Name = upstreamName
257+
upstream.ID = id.GenID(upstreamName)
251258
upstreams = append(upstreams, upstream)
252259
}
253260

@@ -259,8 +266,16 @@ func (t *Translator) buildUpstream(tctx *provider.TranslateContext, service *adc
259266
// the first valid upstream is used as service.upstream;
260267
// the others are configured in the traffic-split plugin
261268
service.Upstream = upstreams[0]
269+
// remove the id and name of the service.upstream, adc schema does not need id and name for it
270+
service.Upstream.ID = ""
271+
service.Upstream.Name = ""
272+
262273
upstreams = upstreams[1:]
263274

275+
if len(upstreams) > 0 {
276+
service.Upstreams = upstreams
277+
}
278+
264279
// set weight in traffic-split for the default upstream
265280
if len(upstreams) > 0 {
266281
weight, err := strconv.Atoi(service.Upstream.Labels["meta_weight"])
@@ -272,15 +287,15 @@ func (t *Translator) buildUpstream(tctx *provider.TranslateContext, service *adc
272287
})
273288
}
274289

275-
// set others upstreams in traffic-split
290+
// set others upstreams in traffic-split using upstream_id
276291
for _, item := range upstreams {
277292
weight, err := strconv.Atoi(item.Labels["meta_weight"])
278293
if err != nil {
279294
weight = apiv2.DefaultWeight
280295
}
281296
weightedUpstreams = append(weightedUpstreams, adc.TrafficSplitConfigRuleWeightedUpstream{
282-
Upstream: item,
283-
Weight: weight,
297+
UpstreamID: item.ID,
298+
Weight: weight,
284299
})
285300
}
286301

internal/adc/translator/httproute.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,24 @@ func (t *Translator) TranslateHTTPRoute(tctx *provider.TranslateContext, httpRou
543543

544544
t.AttachBackendTrafficPolicyToUpstream(backend.BackendRef, tctx.BackendTrafficPolicies, upstream)
545545
upstream.Nodes = upNodes
546+
547+
var (
548+
kind string
549+
port int32
550+
)
551+
if backend.Kind == nil {
552+
kind = "Service"
553+
} else {
554+
kind = string(*backend.Kind)
555+
}
556+
if backend.Port != nil {
557+
port = int32(*backend.Port)
558+
}
559+
namespace := string(*backend.Namespace)
560+
name := string(backend.Name)
561+
upstreamName := adctypes.ComposeUpstreamNameForBackendRef(kind, namespace, name, port)
562+
upstream.Name = upstreamName
563+
upstream.ID = id.GenID(upstreamName)
546564
upstreams = append(upstreams, upstream)
547565
}
548566

@@ -554,11 +572,22 @@ func (t *Translator) TranslateHTTPRoute(tctx *provider.TranslateContext, httpRou
554572
} else if len(upstreams) == 1 {
555573
// Single backend - use directly as service upstream
556574
service.Upstream = upstreams[0]
575+
// remove the id and name of the service.upstream, adc schema does not need id and name for it
576+
service.Upstream.ID = ""
577+
service.Upstream.Name = ""
557578
} else {
558579
// Multiple backends - use traffic-split plugin
559580
service.Upstream = upstreams[0]
581+
// remove the id and name of the service.upstream, adc schema does not need id and name for it
582+
service.Upstream.ID = ""
583+
service.Upstream.Name = ""
584+
560585
upstreams = upstreams[1:]
561586

587+
if len(upstreams) > 0 {
588+
service.Upstreams = upstreams
589+
}
590+
562591
// Set weight in traffic-split for the default upstream
563592
weight := apiv2.DefaultWeight
564593
if rule.BackendRefs[0].Weight != nil {
@@ -568,16 +597,16 @@ func (t *Translator) TranslateHTTPRoute(tctx *provider.TranslateContext, httpRou
568597
Weight: weight,
569598
})
570599

571-
// Set other upstreams in traffic-split
600+
// Set other upstreams in traffic-split using upstream_id
572601
for i, upstream := range upstreams {
573602
weight := apiv2.DefaultWeight
574603
// get weight from the backend refs starting from the second backend
575604
if i+1 < len(rule.BackendRefs) && rule.BackendRefs[i+1].Weight != nil {
576605
weight = int(*rule.BackendRefs[i+1].Weight)
577606
}
578607
weightedUpstreams = append(weightedUpstreams, adctypes.TrafficSplitConfigRuleWeightedUpstream{
579-
Upstream: upstream,
580-
Weight: weight,
608+
UpstreamID: upstream.ID,
609+
Weight: weight,
581610
})
582611
}
583612

0 commit comments

Comments
 (0)