Some checks failed
codecov / upload (push) Failing after 13m59s
CodeQL / Analyze (push) Failing after 1s
govulncheck / govulncheck (.) (push) Failing after 1s
govulncheck / govulncheck (./cmd/protoc-gen-go-grpc) (push) Failing after 1s
govulncheck / govulncheck (./gcp/observability) (push) Failing after 1s
govulncheck / govulncheck (./security/advancedtls) (push) Failing after 1s
govulncheck / govulncheck (./stats/opencensus) (push) Failing after 1s
Testing / tests (arm, latest) (push) Waiting to run
Testing / vet-proto (push) Failing after 1s
Testing / extras (latest) (push) Failing after 1s
Testing / static checks (latest-1) (push) Failing after 1s
Testing / tests (-race, latest) (push) Failing after 1s
Testing / tests (i386, latest) (push) Failing after 1s
Testing / tests (latest) (push) Failing after 1s
Testing / tests (latest-1) (push) Failing after 1s
Lock Threads / lock (push) Failing after 1s
Stale bot / stale (push) Failing after 0s
1722 lines
53 KiB
Go
1722 lines
53 KiB
Go
/*
|
|
*
|
|
* Copyright 2021 gRPC authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package xdsresource
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"net"
|
|
"strconv"
|
|
"testing"
|
|
|
|
v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
|
v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
|
|
v3discoverypb "github.com/envoyproxy/go-control-plane/envoy/service/discovery/v3"
|
|
v3typepb "github.com/envoyproxy/go-control-plane/envoy/type/v3"
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/google/go-cmp/cmp/cmpopts"
|
|
"google.golang.org/grpc/experimental/balancer/hostname"
|
|
"google.golang.org/grpc/internal/envconfig"
|
|
"google.golang.org/grpc/internal/pretty"
|
|
"google.golang.org/grpc/internal/testutils"
|
|
"google.golang.org/grpc/internal/xds/clients"
|
|
"google.golang.org/grpc/internal/xds/xdsclient/xdsresource/version"
|
|
"google.golang.org/grpc/resolver"
|
|
"google.golang.org/grpc/resolver/ringhash"
|
|
"google.golang.org/protobuf/proto"
|
|
"google.golang.org/protobuf/types/known/anypb"
|
|
"google.golang.org/protobuf/types/known/structpb"
|
|
"google.golang.org/protobuf/types/known/wrapperspb"
|
|
)
|
|
|
|
// enableA86 enables A86 support for the duration of the test by:
|
|
// 1. Setting the GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT env var to true.
|
|
// 2. Registering the proxy address converter (and restore original
|
|
// on cleanup).
|
|
func enableA86(t *testing.T) {
|
|
testutils.SetEnvConfig(t, &envconfig.XDSHTTPConnectEnabled, true)
|
|
cleanup, err := RegisterMetadataConverterForTesting(version.V3AddressURL)
|
|
if err != nil {
|
|
t.Fatalf("RegisterMetadataConverterForTesting(%q) failed: %v", version.V3AddressURL, err)
|
|
}
|
|
t.Cleanup(cleanup)
|
|
}
|
|
|
|
// disableA86 disables A86 support for the duration of the test by:
|
|
// 1. Setting the GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT env var to false.
|
|
// 2. Unregistering the proxy address converter for the duration of the test
|
|
// (and restoring the original on cleanup).
|
|
func disableA86(t *testing.T) {
|
|
testutils.SetEnvConfig(t, &envconfig.XDSHTTPConnectEnabled, false)
|
|
cleanup := UnregisterMetadataConverterForTesting(version.V3AddressURL)
|
|
t.Cleanup(cleanup)
|
|
}
|
|
|
|
func buildResolverEndpoint(addr []string, host string) resolver.Endpoint {
|
|
address := []resolver.Address{}
|
|
for _, a := range addr {
|
|
address = append(address, resolver.Address{Addr: a})
|
|
}
|
|
resolverEndpoint := resolver.Endpoint{Addresses: address}
|
|
resolverEndpoint = hostname.Set(resolverEndpoint, host)
|
|
return resolverEndpoint
|
|
}
|
|
|
|
func (s) TestEDSParseRespProto(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
m *v3endpointpb.ClusterLoadAssignment
|
|
want EndpointsUpdate
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "missing-priority",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil)
|
|
clab0.addLocality("locality-2", 1, 2, []endpointOpts{{addrWithPort: "addr2:159"}}, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "missing-locality-ID",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
clab0.addLocality("", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "zero-endpoint-weight",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
clab0.addLocality("locality-0", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, &addLocalityOptions{Weight: []uint32{0}})
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "duplicate-locality-in-the-same-priority",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
clab0.addLocality("locality-0", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil)
|
|
clab0.addLocality("locality-0", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil) // Duplicate locality with the same priority.
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "missing locality weight",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints1 := []endpointOpts{{addrWithPort: "addr1:314"}}
|
|
locOption1 := &addLocalityOptions{Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_HEALTHY}}
|
|
clab0.addLocality("locality-1", 0, 1, endpoints1, locOption1)
|
|
endpoints2 := []endpointOpts{{addrWithPort: "addr2:159"}}
|
|
locOption2 := &addLocalityOptions{Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_HEALTHY}}
|
|
clab0.addLocality("locality-2", 0, 0, endpoints2, locOption2)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{},
|
|
},
|
|
{
|
|
name: "max sum of endpoint weights within a locality exceeded",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{
|
|
{addrWithPort: "addr1:314"},
|
|
{addrWithPort: "addr2:159"},
|
|
}
|
|
locOption := &addLocalityOptions{
|
|
Weight: []uint32{math.MaxUint32, 1},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, locOption)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "max sum of weights at the same priority exceeded",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil)
|
|
clab0.addLocality("locality-2", 4294967295, 1, []endpointOpts{{addrWithPort: "addr2:159"}}, nil)
|
|
clab0.addLocality("locality-3", 1, 1, []endpointOpts{{addrWithPort: "addr2:88"}}, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "duplicate endpoint address",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr:997"}}, nil)
|
|
clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr:997"}}, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "unsupported-drop-denominator",
|
|
m: &v3endpointpb.ClusterLoadAssignment{
|
|
ClusterName: "test",
|
|
Policy: &v3endpointpb.ClusterLoadAssignment_Policy{
|
|
DropOverloads: []*v3endpointpb.ClusterLoadAssignment_Policy_DropOverload{{
|
|
Category: "test-drop",
|
|
DropPercentage: &v3typepb.FractionalPercent{
|
|
Numerator: 1,
|
|
Denominator: v3typepb.FractionalPercent_DenominatorType(7),
|
|
},
|
|
}},
|
|
},
|
|
},
|
|
want: EndpointsUpdate{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "good",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints1 := []endpointOpts{{addrWithPort: "addr1:314", hostname: "addr1"}}
|
|
locOption1 := &addLocalityOptions{
|
|
Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_UNHEALTHY},
|
|
Weight: []uint32{271},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 1, endpoints1, locOption1)
|
|
endpoints2 := []endpointOpts{{addrWithPort: "addr2:159", hostname: "addr2"}}
|
|
locOption2 := &addLocalityOptions{
|
|
Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_DRAINING},
|
|
Weight: []uint32{828},
|
|
}
|
|
clab0.addLocality("locality-2", 1, 0, endpoints2, locOption2)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{
|
|
Drops: nil,
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnhealthy,
|
|
Weight: 271,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 1,
|
|
Weight: 1,
|
|
},
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr2:159"}, "addr2"),
|
|
HealthStatus: EndpointHealthStatusDraining,
|
|
Weight: 828,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-2"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "good duplicate locality with different priority",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints1 := []endpointOpts{{addrWithPort: "addr1:314", hostname: "addr1"}}
|
|
locOption1 := &addLocalityOptions{
|
|
Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_UNHEALTHY},
|
|
Weight: []uint32{271},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 1, endpoints1, locOption1)
|
|
// Same locality name, but with different priority.
|
|
endpoints2 := []endpointOpts{{addrWithPort: "addr2:159", hostname: "addr2"}}
|
|
locOption2 := &addLocalityOptions{
|
|
Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_DRAINING},
|
|
Weight: []uint32{828},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints2, locOption2)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{
|
|
Drops: nil,
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnhealthy,
|
|
Weight: 271,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 1,
|
|
Weight: 1,
|
|
},
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr2:159"}, "addr2"),
|
|
HealthStatus: EndpointHealthStatusDraining,
|
|
Weight: 828,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := parseEDSRespProto(tt.m)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Fatalf("parseEDSRespProto() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
if d := cmp.Diff(got, tt.want, cmpopts.EquateEmpty()); d != "" {
|
|
t.Errorf("parseEDSRespProto() got = %v, want %v, diff: %v", got, tt.want, d)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s) TestEDSParseRespProtoAdditionalAddrs(t *testing.T) {
|
|
origDualstackEndpointsEnabled := envconfig.XDSDualstackEndpointsEnabled
|
|
defer func() {
|
|
envconfig.XDSDualstackEndpointsEnabled = origDualstackEndpointsEnabled
|
|
}()
|
|
envconfig.XDSDualstackEndpointsEnabled = true
|
|
|
|
tests := []struct {
|
|
name string
|
|
m *v3endpointpb.ClusterLoadAssignment
|
|
want EndpointsUpdate
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "duplicate primary address in self additional addresses",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr:998", additionalAddrWithPorts: []string{"addr:998"}}}, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "duplicate primary address in other locality additional addresses",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr:997"}}, nil)
|
|
clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr:998", additionalAddrWithPorts: []string{"addr:997"}}}, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "duplicate additional address in self additional addresses",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr:998", additionalAddrWithPorts: []string{"addr:999", "addr:999"}}}, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "duplicate additional address in other locality additional addresses",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
clab0.addLocality("locality-1", 1, 1, []endpointOpts{{addrWithPort: "addr:997", additionalAddrWithPorts: []string{"addr:1000"}}}, nil)
|
|
clab0.addLocality("locality-2", 1, 0, []endpointOpts{{addrWithPort: "addr:998", additionalAddrWithPorts: []string{"addr:1000"}}}, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "multiple localities",
|
|
m: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints1 := []endpointOpts{{addrWithPort: "addr1:997", additionalAddrWithPorts: []string{"addr1:1000"}, hostname: "addr1"}}
|
|
locOption1 := &addLocalityOptions{
|
|
Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_UNHEALTHY},
|
|
Weight: []uint32{271},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 1, endpoints1, locOption1)
|
|
endpoints2 := []endpointOpts{{addrWithPort: "addr2:998", additionalAddrWithPorts: []string{"addr2:1000"}, hostname: "addr2"}}
|
|
locOption2 := &addLocalityOptions{
|
|
Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_HEALTHY},
|
|
Weight: []uint32{828},
|
|
}
|
|
clab0.addLocality("locality-2", 1, 0, endpoints2, locOption2)
|
|
return clab0.Build()
|
|
}(),
|
|
want: EndpointsUpdate{
|
|
Drops: nil,
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:997", "addr1:1000"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnhealthy,
|
|
Weight: 271,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 1,
|
|
Weight: 1,
|
|
},
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr2:998", "addr2:1000"}, "addr2"),
|
|
HealthStatus: EndpointHealthStatusHealthy,
|
|
Weight: 828,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-2"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := parseEDSRespProto(tt.m)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Fatalf("parseEDSRespProto() error = %v, wantErr %v", err, tt.wantErr)
|
|
}
|
|
if d := cmp.Diff(got, tt.want, cmpopts.EquateEmpty()); d != "" {
|
|
t.Errorf("parseEDSRespProto() got = %v, want %v, diff: %v", got, tt.want, d)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s) TestUnmarshalEndpointHashKey(t *testing.T) {
|
|
baseCLA := &v3endpointpb.ClusterLoadAssignment{
|
|
ClusterName: "test-cluster",
|
|
Endpoints: []*v3endpointpb.LocalityLbEndpoints{
|
|
{
|
|
Locality: &v3corepb.Locality{Region: "r"},
|
|
LbEndpoints: []*v3endpointpb.LbEndpoint{
|
|
{
|
|
HostIdentifier: &v3endpointpb.LbEndpoint_Endpoint{
|
|
Endpoint: &v3endpointpb.Endpoint{
|
|
Address: &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "test-address",
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{
|
|
PortValue: 8080,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
LoadBalancingWeight: &wrapperspb.UInt32Value{Value: 1},
|
|
},
|
|
},
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
metadata *v3corepb.Metadata
|
|
wantHashKey string
|
|
compatEnvVar bool
|
|
}{
|
|
{
|
|
name: "no metadata",
|
|
metadata: nil,
|
|
wantHashKey: "",
|
|
},
|
|
{
|
|
name: "empty metadata",
|
|
metadata: &v3corepb.Metadata{},
|
|
wantHashKey: "",
|
|
},
|
|
{
|
|
name: "filter metadata without envoy.lb",
|
|
metadata: &v3corepb.Metadata{
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"test-filter": {},
|
|
},
|
|
},
|
|
wantHashKey: "",
|
|
},
|
|
{
|
|
name: "nil envoy.lb",
|
|
metadata: &v3corepb.Metadata{
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"envoy.lb": nil,
|
|
},
|
|
},
|
|
wantHashKey: "",
|
|
},
|
|
{
|
|
name: "envoy.lb without hash key",
|
|
metadata: &v3corepb.Metadata{
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"envoy.lb": {
|
|
Fields: map[string]*structpb.Value{
|
|
"hash_key": {
|
|
Kind: &structpb.Value_NumberValue{NumberValue: 123.0},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
wantHashKey: "",
|
|
},
|
|
{
|
|
name: "envoy.lb with hash key, compat mode off",
|
|
metadata: &v3corepb.Metadata{
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"envoy.lb": {
|
|
Fields: map[string]*structpb.Value{
|
|
"hash_key": {
|
|
Kind: &structpb.Value_StringValue{StringValue: "test-hash-key"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
wantHashKey: "test-hash-key",
|
|
},
|
|
{
|
|
name: "envoy.lb with hash key, compat mode on",
|
|
metadata: &v3corepb.Metadata{
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"envoy.lb": {
|
|
Fields: map[string]*structpb.Value{
|
|
"hash_key": {
|
|
Kind: &structpb.Value_StringValue{StringValue: "test-hash-key"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
wantHashKey: "",
|
|
compatEnvVar: true,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
testutils.SetEnvConfig(t, &envconfig.XDSEndpointHashKeyBackwardCompat, test.compatEnvVar)
|
|
|
|
cla := proto.Clone(baseCLA).(*v3endpointpb.ClusterLoadAssignment)
|
|
cla.Endpoints[0].LbEndpoints[0].Metadata = test.metadata
|
|
marshalledCLA := testutils.MarshalAny(t, cla)
|
|
_, update, err := unmarshalEndpointsResource(marshalledCLA)
|
|
if err != nil {
|
|
t.Fatalf("unmarshalEndpointsResource() got error = %v, want success", err)
|
|
}
|
|
got := ringhash.HashKey(update.Localities[0].Endpoints[0].ResolverEndpoint)
|
|
if got != test.wantHashKey {
|
|
t.Errorf("unmarshalEndpointResource() endpoint hash key: got %s, want %s", got, test.wantHashKey)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (s) TestUnmarshalEndpoints(t *testing.T) {
|
|
enableA86(t)
|
|
var v3EndpointsAny = testutils.MarshalAny(t, func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints1 := []endpointOpts{{addrWithPort: "addr1:314", hostname: "addr1"}}
|
|
locOption1 := &addLocalityOptions{
|
|
Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_UNHEALTHY},
|
|
Weight: []uint32{271},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 1, endpoints1, locOption1)
|
|
endpoints2 := []endpointOpts{{addrWithPort: "addr2:159", hostname: "addr2"}}
|
|
locOption2 := &addLocalityOptions{
|
|
Health: []v3corepb.HealthStatus{v3corepb.HealthStatus_DRAINING},
|
|
Weight: []uint32{828},
|
|
}
|
|
clab0.addLocality("locality-2", 1, 0, endpoints2, locOption2)
|
|
return clab0.Build()
|
|
}())
|
|
|
|
tests := []struct {
|
|
name string
|
|
resource *anypb.Any
|
|
wantName string
|
|
wantUpdate EndpointsUpdate
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "non-clusterLoadAssignment_resourcetype",
|
|
resource: &anypb.Any{TypeUrl: version.V3HTTPConnManagerURL},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "badly_marshaled_clusterLoadAssignment_resource",
|
|
resource: &anypb.Any{
|
|
TypeUrl: version.V3EndpointsURL,
|
|
Value: []byte{1, 2, 3, 4},
|
|
},
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "bad_endpoints_resource",
|
|
resource: testutils.MarshalAny(t, func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil)
|
|
clab0.addLocality("locality-2", 1, 2, []endpointOpts{{addrWithPort: "addr2:159"}}, nil)
|
|
return clab0.Build()
|
|
}()),
|
|
wantName: "test",
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "endpoint_resource_with_empty_cluster_name",
|
|
resource: testutils.MarshalAny(t, func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("", nil)
|
|
clab0.addLocality("locality-1", 1, 0, []endpointOpts{{addrWithPort: "addr1:314"}}, nil)
|
|
clab0.addLocality("locality-2", 1, 2, []endpointOpts{{addrWithPort: "addr2:159"}}, nil)
|
|
return clab0.Build()
|
|
}()),
|
|
wantName: "",
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "v3_endpoints",
|
|
resource: v3EndpointsAny,
|
|
wantName: "test",
|
|
wantUpdate: EndpointsUpdate{
|
|
Drops: nil,
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnhealthy,
|
|
Weight: 271,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 1,
|
|
Weight: 1,
|
|
},
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr2:159"}, "addr2"),
|
|
HealthStatus: EndpointHealthStatusDraining,
|
|
Weight: 828,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-2"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
Raw: v3EndpointsAny,
|
|
},
|
|
},
|
|
{
|
|
name: "v3_endpoints_wrapped",
|
|
resource: testutils.MarshalAny(t, &v3discoverypb.Resource{Resource: v3EndpointsAny}),
|
|
wantName: "test",
|
|
wantUpdate: EndpointsUpdate{
|
|
Drops: nil,
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnhealthy,
|
|
Weight: 271,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 1,
|
|
Weight: 1,
|
|
},
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr2:159"}, "addr2"),
|
|
HealthStatus: EndpointHealthStatusDraining,
|
|
Weight: 828,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-2"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
Raw: v3EndpointsAny,
|
|
},
|
|
},
|
|
}
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
name, update, err := unmarshalEndpointsResource(test.resource)
|
|
if (err != nil) != test.wantErr {
|
|
t.Fatalf("unmarshalEndpointsResource(%s), got err: %v, wantErr: %v", pretty.ToJSON(test.resource), err, test.wantErr)
|
|
}
|
|
if name != test.wantName {
|
|
t.Errorf("unmarshalEndpointsResource(%s), got name: %s, want: %s", pretty.ToJSON(test.resource), name, test.wantName)
|
|
}
|
|
if diff := cmp.Diff(update, test.wantUpdate, cmpOpts); diff != "" {
|
|
t.Errorf("unmarshalEndpointsResource(%s), got unexpected update, diff (-got +want): %v", pretty.ToJSON(test.resource), diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Tests custom metadata parsing for success cases when the
|
|
// GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT environment variable is set.
|
|
func (s) TestEDSParseRespProto_HTTP_Connect_CustomMetadata_EnvVarOn(t *testing.T) {
|
|
enableA86(t)
|
|
tests := []struct {
|
|
name string
|
|
endpointProto *v3endpointpb.ClusterLoadAssignment
|
|
wantEndpoint EndpointsUpdate
|
|
}{
|
|
{
|
|
name: "typed_filter_metadata_in_endpoint",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{
|
|
addrWithPort: "addr1:314",
|
|
metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"test-key": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "1.2.3.4",
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{
|
|
PortValue: 1111,
|
|
}},
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
hostname: "addr1",
|
|
}}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
Metadata: map[string]any{
|
|
"test-key": ProxyAddressMetadataValue{
|
|
Address: "1.2.3.4:1111",
|
|
},
|
|
},
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "filter_metadata_in_endpoint",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{
|
|
addrWithPort: "addr1:314",
|
|
metadata: &v3corepb.Metadata{
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"test-key": {
|
|
Fields: map[string]*structpb.Value{
|
|
"key": {
|
|
Kind: &structpb.Value_NumberValue{NumberValue: 123.0},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
hostname: "addr1",
|
|
}}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
Metadata: map[string]any{
|
|
"test-key": StructMetadataValue{Data: map[string]any{
|
|
"key": float64(123),
|
|
}},
|
|
},
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "typed_filter_metadata_in_locality",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{addrWithPort: "addr1:314", hostname: "addr1"}}
|
|
locOption := &addLocalityOptions{
|
|
Metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"test-key": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "1.2.3.4",
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{
|
|
PortValue: 1111,
|
|
}},
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, locOption)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
Metadata: map[string]any{
|
|
"test-key": ProxyAddressMetadataValue{
|
|
Address: "1.2.3.4:1111",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "filter_metadata_in_locality",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{addrWithPort: "addr1:314", hostname: "addr1"}}
|
|
locOption := &addLocalityOptions{
|
|
Metadata: &v3corepb.Metadata{
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"test-key": {
|
|
Fields: map[string]*structpb.Value{
|
|
"key": {
|
|
Kind: &structpb.Value_NumberValue{NumberValue: 123.0},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, locOption)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
Metadata: map[string]any{
|
|
"test-key": StructMetadataValue{Data: map[string]any{
|
|
"key": float64(123),
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "typed_filter_metadata_over_filter_metadata_in_endpoint",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{
|
|
addrWithPort: "addr1:314",
|
|
metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"test-key": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "1.2.3.4",
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{
|
|
PortValue: 1111,
|
|
}},
|
|
},
|
|
}),
|
|
},
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"test-key": {
|
|
Fields: map[string]*structpb.Value{
|
|
"key": {
|
|
Kind: &structpb.Value_NumberValue{NumberValue: 123.0},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
hostname: "addr1",
|
|
}}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
Metadata: map[string]any{
|
|
"test-key": ProxyAddressMetadataValue{
|
|
Address: "1.2.3.4:1111",
|
|
},
|
|
},
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "typed_filter_metadata_over_filter_metadata_in_locality",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{addrWithPort: "addr1:314", hostname: "addr1"}}
|
|
locOption := &addLocalityOptions{
|
|
Metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"test-key": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "1.2.3.4",
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{
|
|
PortValue: 1111,
|
|
}},
|
|
},
|
|
}),
|
|
},
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"test-key": {
|
|
Fields: map[string]*structpb.Value{
|
|
"key": {
|
|
Kind: &structpb.Value_NumberValue{NumberValue: 123.0},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, locOption)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
Metadata: map[string]any{
|
|
"test-key": ProxyAddressMetadataValue{
|
|
Address: "1.2.3.4:1111",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "both_filter_and_typed_filter_metadata_in_endpoint",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{
|
|
addrWithPort: "addr1:314",
|
|
metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"test-key": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "1.2.3.4",
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{
|
|
PortValue: 1111,
|
|
}},
|
|
},
|
|
}),
|
|
},
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"another-test-key": {
|
|
Fields: map[string]*structpb.Value{
|
|
"key": {
|
|
Kind: &structpb.Value_NumberValue{NumberValue: 123.0},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
hostname: "addr1",
|
|
}}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
Metadata: map[string]any{
|
|
"test-key": ProxyAddressMetadataValue{
|
|
Address: "1.2.3.4:1111",
|
|
},
|
|
"another-test-key": StructMetadataValue{Data: map[string]any{
|
|
"key": float64(123),
|
|
}},
|
|
},
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "both_filter_and_typed_filter_metadata_in_locality",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{addrWithPort: "addr1:314", hostname: "addr1"}}
|
|
locOption := &addLocalityOptions{
|
|
Metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"test-key": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "1.2.3.4",
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{
|
|
PortValue: 1111,
|
|
}},
|
|
},
|
|
}),
|
|
},
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"another-test-key": {
|
|
Fields: map[string]*structpb.Value{
|
|
"key": {
|
|
Kind: &structpb.Value_NumberValue{NumberValue: 123.0},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, locOption)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
Metadata: map[string]any{
|
|
"test-key": ProxyAddressMetadataValue{
|
|
Address: "1.2.3.4:1111",
|
|
},
|
|
"another-test-key": StructMetadataValue{Data: map[string]any{
|
|
"key": float64(123),
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := parseEDSRespProto(tt.endpointProto)
|
|
if err != nil {
|
|
t.Fatalf("parseEDSRespProto() failed: %v", err)
|
|
}
|
|
if diff := cmp.Diff(tt.wantEndpoint, got, cmpopts.EquateEmpty()); diff != "" {
|
|
t.Errorf("parseEDSRespProto() returned unexpected diff (-want +got):\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Tests custom metadata parsing for success cases when the
|
|
// GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT environment variable is not set and
|
|
// GRPC_XDS_ENDPOINT_HASH_KEY_BACKWARD_COMPAT is set to true (disabling A76).
|
|
func (s) TestEDSParseRespProto_HTTP_Connect_CustomMetadata_EnvVarOff(t *testing.T) {
|
|
disableA86(t)
|
|
testutils.SetEnvConfig(t, &envconfig.XDSEndpointHashKeyBackwardCompat, true)
|
|
tests := []struct {
|
|
name string
|
|
endpointProto *v3endpointpb.ClusterLoadAssignment
|
|
wantEndpoint EndpointsUpdate
|
|
}{
|
|
{
|
|
name: "typed_filter_metadata_in_endpoint",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{
|
|
addrWithPort: "addr1:314",
|
|
metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"test-key": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "1.2.3.4",
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{
|
|
PortValue: 1111,
|
|
}},
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
hostname: "addr1",
|
|
}}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "filter_metadata_in_endpoint",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{
|
|
addrWithPort: "addr1:314",
|
|
metadata: &v3corepb.Metadata{
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"test-key": {
|
|
Fields: map[string]*structpb.Value{
|
|
"key": {
|
|
Kind: &structpb.Value_NumberValue{NumberValue: 123.0},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
hostname: "addr1",
|
|
}}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "typed_filter_metadata_in_locality",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{addrWithPort: "addr1:314", hostname: "addr1"}}
|
|
locOption := &addLocalityOptions{
|
|
Metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"test-key": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "1.2.3.4",
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{
|
|
PortValue: 1111,
|
|
}},
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, locOption)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "filter_metadata_in_locality",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{addrWithPort: "addr1:314", hostname: "addr1"}}
|
|
locOption := &addLocalityOptions{
|
|
Metadata: &v3corepb.Metadata{
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"test-key": {
|
|
Fields: map[string]*structpb.Value{
|
|
"key": {
|
|
Kind: &structpb.Value_NumberValue{NumberValue: 123.0},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, locOption)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "both_filter_and_typed_filter_metadata_in_endpoint",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{
|
|
addrWithPort: "addr1:314",
|
|
metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"test-key": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "1.2.3.4",
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{
|
|
PortValue: 1111,
|
|
}},
|
|
},
|
|
}),
|
|
},
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"another-test-key": {
|
|
Fields: map[string]*structpb.Value{
|
|
"key": {
|
|
Kind: &structpb.Value_NumberValue{NumberValue: 123.0},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
hostname: "addr1",
|
|
}}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "both_filter_and_typed_filter_metadata_in_locality",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{addrWithPort: "addr1:314", hostname: "addr1"}}
|
|
locOption := &addLocalityOptions{
|
|
Metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"test-key": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "1.2.3.4",
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{
|
|
PortValue: 1111,
|
|
}},
|
|
},
|
|
}),
|
|
},
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"another-test-key": {
|
|
Fields: map[string]*structpb.Value{
|
|
"key": {
|
|
Kind: &structpb.Value_NumberValue{NumberValue: 123.0},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, locOption)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "converter_failure_is_not_triggerred",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{
|
|
addrWithPort: "addr1:314",
|
|
metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"envoy.http11_proxy_transport_socket.proxy_address": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "invalid",
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
hostname: "addr1",
|
|
}}
|
|
locOption := &addLocalityOptions{
|
|
Metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"envoy.http11_proxy_transport_socket.proxy_address": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "invalid",
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, locOption)
|
|
return clab0.Build()
|
|
}(),
|
|
wantEndpoint: EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := parseEDSRespProto(tt.endpointProto)
|
|
if err != nil {
|
|
t.Fatalf("parseEDSRespProto() failed: %v", err)
|
|
}
|
|
if diff := cmp.Diff(tt.wantEndpoint, got, cmpopts.EquateEmpty()); diff != "" {
|
|
t.Errorf("parseEDSRespProto() returned unexpected diff (-want +got):\n%s", diff)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Tests custom metadata parsing for converter failure cases when the
|
|
// GRPC_EXPERIMENTAL_XDS_HTTP_CONNECT environment variable is set.
|
|
func (s) TestEDSParseRespProto_HTTP_Connect_CustomMetadata_ConverterFailure(t *testing.T) {
|
|
enableA86(t)
|
|
tests := []struct {
|
|
name string
|
|
endpointProto *v3endpointpb.ClusterLoadAssignment
|
|
}{
|
|
{
|
|
name: "converter_failure_in_endpoint",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{
|
|
addrWithPort: "addr1:314",
|
|
metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"envoy.http11_proxy_transport_socket.proxy_address": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "invalid",
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
}}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, nil)
|
|
return clab0.Build()
|
|
}(),
|
|
},
|
|
{
|
|
name: "converter_failure_in_locality",
|
|
endpointProto: func() *v3endpointpb.ClusterLoadAssignment {
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{addrWithPort: "addr1:314"}}
|
|
locOption := &addLocalityOptions{
|
|
Metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"envoy.http11_proxy_transport_socket.proxy_address": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "invalid",
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
},
|
|
}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, locOption)
|
|
return clab0.Build()
|
|
}(),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if _, err := parseEDSRespProto(tt.endpointProto); err == nil {
|
|
t.Fatalf("parseEDSRespProto() did not return error when expected")
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// Tests metadata parsing when HTTP Connect is enabled but A76 hash key is
|
|
// disabled (backward compat mode). This verifies that:
|
|
// - Metadata parsing happens (TypedFilterMetadata + FilterMetadata)
|
|
// - Hash key is NOT extracted from envoy.lb
|
|
func (s) TestEDSParseRespProto_HTTP_Connect_On_HashKeyBackwardCompat_On(t *testing.T) {
|
|
enableA86(t)
|
|
testutils.SetEnvConfig(t, &envconfig.XDSEndpointHashKeyBackwardCompat, true)
|
|
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{
|
|
addrWithPort: "addr1:314",
|
|
metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"envoy.http11_proxy_transport_socket.proxy_address": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "1.2.3.4",
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{
|
|
PortValue: 1111,
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"envoy.lb": {
|
|
Fields: map[string]*structpb.Value{
|
|
"hash_key": {
|
|
Kind: &structpb.Value_StringValue{StringValue: "test-hash-key"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
hostname: "addr1",
|
|
}}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, nil)
|
|
|
|
got, err := parseEDSRespProto(clab0.Build())
|
|
if err != nil {
|
|
t.Fatalf("parseEDSRespProto() failed: %v", err)
|
|
}
|
|
|
|
wantEndpoint := EndpointsUpdate{
|
|
Localities: []Locality{
|
|
{
|
|
Endpoints: []Endpoint{{
|
|
ResolverEndpoint: buildResolverEndpoint([]string{"addr1:314"}, "addr1"),
|
|
HealthStatus: EndpointHealthStatusUnknown,
|
|
Weight: 1,
|
|
Metadata: map[string]any{
|
|
"envoy.http11_proxy_transport_socket.proxy_address": ProxyAddressMetadataValue{
|
|
Address: "1.2.3.4:1111",
|
|
},
|
|
"envoy.lb": StructMetadataValue{Data: map[string]any{
|
|
"hash_key": "test-hash-key",
|
|
}},
|
|
},
|
|
}},
|
|
ID: clients.Locality{SubZone: "locality-1"},
|
|
Priority: 0,
|
|
Weight: 1,
|
|
},
|
|
},
|
|
}
|
|
|
|
if diff := cmp.Diff(wantEndpoint, got, cmpopts.EquateEmpty()); diff != "" {
|
|
t.Errorf("parseEDSRespProto() returned unexpected diff (-want +got):\n%s", diff)
|
|
}
|
|
|
|
// Verify hash key is NOT extracted when backward compat is on.
|
|
hashKey := ringhash.HashKey(got.Localities[0].Endpoints[0].ResolverEndpoint)
|
|
if hashKey != "" {
|
|
t.Errorf("Expected empty hash key with backward compat on, got %q", hashKey)
|
|
}
|
|
}
|
|
|
|
// Tests that when A76 is enabled but A86 is disabled, invalid typed metadata
|
|
// does not cause a parsing failure, and hash key is still extracted.
|
|
func (s) TestEDSParseRespProto_HTTP_Connect_Off_HashKeyBackwardCompat_Off_InvalidTypedMetadata(t *testing.T) {
|
|
disableA86(t)
|
|
testutils.SetEnvConfig(t, &envconfig.XDSEndpointHashKeyBackwardCompat, false) // A76 on
|
|
|
|
clab0 := newClaBuilder("test", nil)
|
|
endpoints := []endpointOpts{{
|
|
addrWithPort: "addr1:314",
|
|
metadata: &v3corepb.Metadata{
|
|
TypedFilterMetadata: map[string]*anypb.Any{
|
|
"envoy.http11_proxy_transport_socket.proxy_address": testutils.MarshalAny(t, &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Address: "invalid", // This would fail conversion if processed.
|
|
},
|
|
},
|
|
}),
|
|
},
|
|
FilterMetadata: map[string]*structpb.Struct{
|
|
"envoy.lb": {
|
|
Fields: map[string]*structpb.Value{
|
|
"hash_key": {
|
|
Kind: &structpb.Value_StringValue{StringValue: "test-hash-key"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
hostname: "addr1",
|
|
}}
|
|
clab0.addLocality("locality-1", 1, 0, endpoints, nil)
|
|
|
|
got, err := parseEDSRespProto(clab0.Build())
|
|
if err != nil {
|
|
t.Fatalf("parseEDSRespProto() failed unexpectedly with A76 on and A86 off: %v", err)
|
|
}
|
|
|
|
// Verify hash key is extracted when A76 is on.
|
|
hashKey := ringhash.HashKey(got.Localities[0].Endpoints[0].ResolverEndpoint)
|
|
if want := "test-hash-key"; hashKey != want {
|
|
t.Errorf("Expected hash key %q with A76 on, got %q", want, hashKey)
|
|
}
|
|
}
|
|
|
|
// claBuilder builds a ClusterLoadAssignment, aka EDS
|
|
// response.
|
|
type claBuilder struct {
|
|
v *v3endpointpb.ClusterLoadAssignment
|
|
}
|
|
|
|
// newClaBuilder creates a claBuilder.
|
|
func newClaBuilder(clusterName string, dropPercents []uint32) *claBuilder {
|
|
var drops []*v3endpointpb.ClusterLoadAssignment_Policy_DropOverload
|
|
for i, d := range dropPercents {
|
|
drops = append(drops, &v3endpointpb.ClusterLoadAssignment_Policy_DropOverload{
|
|
Category: fmt.Sprintf("test-drop-%d", i),
|
|
DropPercentage: &v3typepb.FractionalPercent{
|
|
Numerator: d,
|
|
Denominator: v3typepb.FractionalPercent_HUNDRED,
|
|
},
|
|
})
|
|
}
|
|
|
|
return &claBuilder{
|
|
v: &v3endpointpb.ClusterLoadAssignment{
|
|
ClusterName: clusterName,
|
|
Policy: &v3endpointpb.ClusterLoadAssignment_Policy{
|
|
DropOverloads: drops,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// addLocalityOptions contains options when adding locality to the builder.
|
|
type addLocalityOptions struct {
|
|
Health []v3corepb.HealthStatus
|
|
Weight []uint32
|
|
Metadata *v3corepb.Metadata
|
|
}
|
|
|
|
type endpointOpts struct {
|
|
addrWithPort string
|
|
additionalAddrWithPorts []string
|
|
metadata *v3corepb.Metadata
|
|
hostname string
|
|
}
|
|
|
|
func addressFromStr(addrWithPort string) *v3corepb.Address {
|
|
host, portStr, err := net.SplitHostPort(addrWithPort)
|
|
if err != nil {
|
|
panic("failed to split " + addrWithPort)
|
|
}
|
|
port, err := strconv.Atoi(portStr)
|
|
if err != nil {
|
|
panic("failed to atoi " + portStr)
|
|
}
|
|
|
|
return &v3corepb.Address{
|
|
Address: &v3corepb.Address_SocketAddress{
|
|
SocketAddress: &v3corepb.SocketAddress{
|
|
Protocol: v3corepb.SocketAddress_TCP,
|
|
Address: host,
|
|
PortSpecifier: &v3corepb.SocketAddress_PortValue{PortValue: uint32(port)},
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// addLocality adds a locality to the builder.
|
|
func (clab *claBuilder) addLocality(subzone string, weight uint32, priority uint32, endpoints []endpointOpts, opts *addLocalityOptions) {
|
|
var lbEndPoints []*v3endpointpb.LbEndpoint
|
|
for i, e := range endpoints {
|
|
var additionalAddrs []*v3endpointpb.Endpoint_AdditionalAddress
|
|
for _, a := range e.additionalAddrWithPorts {
|
|
additionalAddrs = append(additionalAddrs, &v3endpointpb.Endpoint_AdditionalAddress{
|
|
Address: addressFromStr(a),
|
|
})
|
|
}
|
|
lbe := &v3endpointpb.LbEndpoint{
|
|
HostIdentifier: &v3endpointpb.LbEndpoint_Endpoint{
|
|
Endpoint: &v3endpointpb.Endpoint{
|
|
Address: addressFromStr(e.addrWithPort),
|
|
AdditionalAddresses: additionalAddrs,
|
|
Hostname: e.hostname,
|
|
},
|
|
},
|
|
Metadata: e.metadata,
|
|
}
|
|
if opts != nil {
|
|
if i < len(opts.Health) {
|
|
lbe.HealthStatus = opts.Health[i]
|
|
}
|
|
if i < len(opts.Weight) {
|
|
lbe.LoadBalancingWeight = &wrapperspb.UInt32Value{Value: opts.Weight[i]}
|
|
}
|
|
}
|
|
lbEndPoints = append(lbEndPoints, lbe)
|
|
}
|
|
|
|
var localityID *v3corepb.Locality
|
|
if subzone != "" {
|
|
localityID = &v3corepb.Locality{
|
|
Region: "",
|
|
Zone: "",
|
|
SubZone: subzone,
|
|
}
|
|
}
|
|
|
|
locality := &v3endpointpb.LocalityLbEndpoints{
|
|
Locality: localityID,
|
|
LbEndpoints: lbEndPoints,
|
|
LoadBalancingWeight: &wrapperspb.UInt32Value{Value: weight},
|
|
Priority: priority,
|
|
}
|
|
if opts != nil {
|
|
locality.Metadata = opts.Metadata
|
|
}
|
|
clab.v.Endpoints = append(clab.v.Endpoints, locality)
|
|
}
|
|
|
|
// Build builds ClusterLoadAssignment.
|
|
func (clab *claBuilder) Build() *v3endpointpb.ClusterLoadAssignment {
|
|
return clab.v
|
|
}
|