Skip to content

Commit 26bb58b

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

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
@@ -29,6 +29,9 @@ concurrency:
2929
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
3030
cancel-in-progress: true
3131

32+
env:
33+
ADC_VERSION: dev
34+
3235
jobs:
3336
e2e-test:
3437
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
@@ -807,3 +808,59 @@ func (c Config) MarshalJSON() ([]byte, error) {
807808
TlsVerify: c.TlsVerify,
808809
})
809810
}
811+
812+
var (
813+
ResolveGranularity = struct {
814+
Endpoint string
815+
Service string
816+
}{
817+
Endpoint: "endpoint",
818+
Service: "service",
819+
}
820+
)
821+
822+
// ComposeUpstreamName uses namespace, name, subset (optional), port, resolveGranularity info to compose
823+
// the upstream name.
824+
// the resolveGranularity is not composited in the upstream name when it is endpoint.
825+
// ref: https://github.com/apache/apisix-ingress-controller/blob/10059afe3e84b693cc61e6df7a0040890a9d16eb/pkg/types/apisix/v1/types.go#L595-L598
826+
func ComposeUpstreamName(namespace, name, subset string, port int32, resolveGranularity string) string {
827+
pstr := strconv.Itoa(int(port))
828+
// FIXME Use sync.Pool to reuse this buffer if the upstream
829+
// name composing code path is hot.
830+
var p []byte
831+
plen := len(namespace) + len(name) + len(pstr) + 2
832+
if subset != "" {
833+
plen = plen + len(subset) + 1
834+
}
835+
if resolveGranularity == ResolveGranularity.Service {
836+
plen = plen + len(resolveGranularity) + 1
837+
}
838+
839+
p = make([]byte, 0, plen)
840+
buf := bytes.NewBuffer(p)
841+
buf.WriteString(namespace)
842+
buf.WriteByte('_')
843+
buf.WriteString(name)
844+
buf.WriteByte('_')
845+
if subset != "" {
846+
buf.WriteString(subset)
847+
buf.WriteByte('_')
848+
}
849+
buf.WriteString(pstr)
850+
if resolveGranularity == ResolveGranularity.Service {
851+
buf.WriteByte('_')
852+
buf.WriteString(resolveGranularity)
853+
}
854+
855+
return buf.String()
856+
}
857+
858+
// ComposeExternalUpstreamName uses ApisixUpstream namespace, name to compose the upstream name.
859+
func ComposeExternalUpstreamName(namespace, name string) string {
860+
return namespace + "_" + name
861+
}
862+
863+
// ComposeUpstreamNameForBackendRef composes upstream name using kind, namespace, name and port.
864+
func ComposeUpstreamNameForBackendRef(kind, namespace, name string, port int32) string {
865+
return fmt.Sprintf("%s_%s_%s_%d", kind, namespace, name, port)
866+
}

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
@@ -234,6 +234,10 @@ func (t *Translator) buildUpstream(tctx *provider.TranslateContext, service *adc
234234
if backend.Weight != nil {
235235
upstream.Labels["meta_weight"] = strconv.FormatInt(int64(*backend.Weight), 10)
236236
}
237+
238+
upstreamName := adc.ComposeUpstreamName(ar.Namespace, backend.ServiceName, backend.Subset, int32(backend.ServicePort.IntValue()), backend.ResolveGranularity)
239+
upstream.Name = upstreamName
240+
upstream.ID = id.GenID(upstreamName)
237241
upstreams = append(upstreams, upstream)
238242
}
239243

@@ -256,6 +260,9 @@ func (t *Translator) buildUpstream(tctx *provider.TranslateContext, service *adc
256260
upstream.Labels["meta_weight"] = strconv.FormatInt(int64(*upstreamRef.Weight), 10)
257261
}
258262

263+
upstreamName := adc.ComposeExternalUpstreamName(upsNN.Namespace, upsNN.Name)
264+
upstream.Name = upstreamName
265+
upstream.ID = id.GenID(upstreamName)
259266
upstreams = append(upstreams, upstream)
260267
}
261268

@@ -267,8 +274,16 @@ func (t *Translator) buildUpstream(tctx *provider.TranslateContext, service *adc
267274
// the first valid upstream is used as service.upstream;
268275
// the others are configured in the traffic-split plugin
269276
service.Upstream = upstreams[0]
277+
// remove the id and name of the service.upstream, adc schema does not need id and name for it
278+
service.Upstream.ID = ""
279+
service.Upstream.Name = ""
280+
270281
upstreams = upstreams[1:]
271282

283+
if len(upstreams) > 0 {
284+
service.Upstreams = upstreams
285+
}
286+
272287
// set weight in traffic-split for the default upstream
273288
if len(upstreams) > 0 {
274289
weight, err := strconv.Atoi(service.Upstream.Labels["meta_weight"])
@@ -280,15 +295,15 @@ func (t *Translator) buildUpstream(tctx *provider.TranslateContext, service *adc
280295
})
281296
}
282297

283-
// set others upstreams in traffic-split
298+
// set others upstreams in traffic-split using upstream_id
284299
for _, item := range upstreams {
285300
weight, err := strconv.Atoi(item.Labels["meta_weight"])
286301
if err != nil {
287302
weight = apiv2.DefaultWeight
288303
}
289304
weightedUpstreams = append(weightedUpstreams, adc.TrafficSplitConfigRuleWeightedUpstream{
290-
Upstream: item,
291-
Weight: weight,
305+
UpstreamID: item.ID,
306+
Weight: weight,
292307
})
293308
}
294309

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)