xds: add new fields to XDSConfig (#3100)
Fields are added in: https://github.com/grpc/grpc-proto/pull/64 Other changes: - Move XDSConfig from internal to balancer - Later we will add a separate config for CDS balancer - generate service_config.pb.go and test with json generated from proto message
This commit is contained in:
59
internal/proto/grpc_service_config/example_test.go
Normal file
59
internal/proto/grpc_service_config/example_test.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//go:generate ./regenerate.sh
|
||||||
|
|
||||||
|
package grpc_service_config_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/jsonpb"
|
||||||
|
wrapperspb "github.com/golang/protobuf/ptypes/wrappers"
|
||||||
|
scpb "google.golang.org/grpc/internal/proto/grpc_service_config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestXdsConfigMarshalToJSON is an example to print json format of xds_config.
|
||||||
|
func TestXdsConfigMarshalToJSON(t *testing.T) {
|
||||||
|
c := &scpb.XdsConfig{
|
||||||
|
ChildPolicy: []*scpb.LoadBalancingConfig{
|
||||||
|
{Policy: &scpb.LoadBalancingConfig_Grpclb{
|
||||||
|
Grpclb: &scpb.GrpcLbConfig{},
|
||||||
|
}},
|
||||||
|
{Policy: &scpb.LoadBalancingConfig_RoundRobin{
|
||||||
|
RoundRobin: &scpb.RoundRobinConfig{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
FallbackPolicy: []*scpb.LoadBalancingConfig{
|
||||||
|
{Policy: &scpb.LoadBalancingConfig_Grpclb{
|
||||||
|
Grpclb: &scpb.GrpcLbConfig{},
|
||||||
|
}},
|
||||||
|
{Policy: &scpb.LoadBalancingConfig_PickFirst{
|
||||||
|
PickFirst: &scpb.PickFirstConfig{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
EdsServiceName: "eds.service.name",
|
||||||
|
LrsLoadReportingServerName: &wrapperspb.StringValue{
|
||||||
|
Value: "lrs.server.name",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
j, err := (&jsonpb.Marshaler{}).MarshalToString(c)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to marshal proto to json: %v", err)
|
||||||
|
}
|
||||||
|
t.Logf(j)
|
||||||
|
}
|
35
internal/proto/grpc_service_config/regenerate.sh
Executable file
35
internal/proto/grpc_service_config/regenerate.sh
Executable file
@ -0,0 +1,35 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Copyright 2019 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.
|
||||||
|
|
||||||
|
set -eux -o pipefail
|
||||||
|
|
||||||
|
TMP=$(mktemp -d)
|
||||||
|
|
||||||
|
function finish {
|
||||||
|
rm -rf "$TMP"
|
||||||
|
}
|
||||||
|
trap finish EXIT
|
||||||
|
|
||||||
|
pushd "$TMP"
|
||||||
|
mkdir -p grpc/service_config
|
||||||
|
curl https://raw.githubusercontent.com/grpc/grpc-proto/master/grpc/service_config/service_config.proto > grpc/service_config/service_config.proto
|
||||||
|
mkdir -p google/rpc
|
||||||
|
curl https://raw.githubusercontent.com/googleapis/googleapis/master/google/rpc/code.proto > google/rpc/code.proto
|
||||||
|
|
||||||
|
protoc --go_out=plugins=grpc,paths=source_relative:. -I. grpc/service_config/*.proto
|
||||||
|
popd
|
||||||
|
rm -f ./*.pb.go
|
||||||
|
cp "$TMP"/grpc/service_config/*.pb.go ./
|
||||||
|
|
1131
internal/proto/grpc_service_config/service_config.pb.go
Normal file
1131
internal/proto/grpc_service_config/service_config.pb.go
Normal file
File diff suppressed because it is too large
Load Diff
117
xds/internal/balancer/config.go
Normal file
117
xds/internal/balancer/config.go
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* Copyright 2019 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 balancer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/balancer"
|
||||||
|
"google.golang.org/grpc/serviceconfig"
|
||||||
|
)
|
||||||
|
|
||||||
|
// XDSConfig represents the loadBalancingConfig section of the service config
|
||||||
|
// for xDS balancers.
|
||||||
|
type XDSConfig struct {
|
||||||
|
serviceconfig.LoadBalancingConfig
|
||||||
|
// BalancerName represents the load balancer to use.
|
||||||
|
BalancerName string
|
||||||
|
// ChildPolicy represents the load balancing config for the child
|
||||||
|
// policy.
|
||||||
|
ChildPolicy *loadBalancingConfig
|
||||||
|
// FallBackPolicy represents the load balancing config for the
|
||||||
|
// fallback.
|
||||||
|
FallBackPolicy *loadBalancingConfig
|
||||||
|
// Name to use in EDS query. If not present, defaults to the server
|
||||||
|
// name from the target URI.
|
||||||
|
EDSServiceName string
|
||||||
|
// LRS server to send load reports to. If not present, load reporting
|
||||||
|
// will be disabled. If set to the empty string, load reporting will
|
||||||
|
// be sent to the same server that we obtained CDS data from.
|
||||||
|
LrsLoadReportingServerName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// xdsConfigJSON is the intermediate unmarshal result of XDSConfig. ChildPolicy
|
||||||
|
// and Fallbackspolicy are post-processed, and for each, the first installed
|
||||||
|
// policy is kept.
|
||||||
|
type xdsConfigJSON struct {
|
||||||
|
BalancerName string
|
||||||
|
ChildPolicy []*loadBalancingConfig
|
||||||
|
FallbackPolicy []*loadBalancingConfig
|
||||||
|
EDSServiceName string
|
||||||
|
LRSLoadReportingServerName string
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON parses the JSON-encoded byte slice in data and stores it in l.
|
||||||
|
// When unmarshalling, we iterate through the childPolicy/fallbackPolicy lists
|
||||||
|
// and select the first LB policy which has been registered.
|
||||||
|
func (l *XDSConfig) UnmarshalJSON(data []byte) error {
|
||||||
|
var configJSON xdsConfigJSON
|
||||||
|
if err := json.Unmarshal(data, &configJSON); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
l.BalancerName = configJSON.BalancerName
|
||||||
|
l.EDSServiceName = configJSON.EDSServiceName
|
||||||
|
l.LrsLoadReportingServerName = configJSON.LRSLoadReportingServerName
|
||||||
|
|
||||||
|
for _, lbcfg := range configJSON.ChildPolicy {
|
||||||
|
if balancer.Get(lbcfg.Name) != nil {
|
||||||
|
l.ChildPolicy = lbcfg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, lbcfg := range configJSON.FallbackPolicy {
|
||||||
|
if balancer.Get(lbcfg.Name) != nil {
|
||||||
|
l.FallBackPolicy = lbcfg
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON returns a JSON encoding of l.
|
||||||
|
func (l *XDSConfig) MarshalJSON() ([]byte, error) {
|
||||||
|
return nil, fmt.Errorf("XDSConfig.MarshalJSON() is unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadBalancingConfig represents a single load balancing config,
|
||||||
|
// stored in JSON format.
|
||||||
|
type loadBalancingConfig struct {
|
||||||
|
Name string
|
||||||
|
Config json.RawMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON returns a JSON encoding of l.
|
||||||
|
func (l *loadBalancingConfig) MarshalJSON() ([]byte, error) {
|
||||||
|
return nil, fmt.Errorf("loadBalancingConfig.MarshalJSON() is unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON parses the JSON-encoded byte slice in data and stores it in l.
|
||||||
|
func (l *loadBalancingConfig) UnmarshalJSON(data []byte) error {
|
||||||
|
var cfg map[string]json.RawMessage
|
||||||
|
if err := json.Unmarshal(data, &cfg); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for name, config := range cfg {
|
||||||
|
l.Name = name
|
||||||
|
l.Config = config
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
@ -34,7 +34,6 @@ import (
|
|||||||
"google.golang.org/grpc/grpclog"
|
"google.golang.org/grpc/grpclog"
|
||||||
"google.golang.org/grpc/resolver"
|
"google.golang.org/grpc/resolver"
|
||||||
"google.golang.org/grpc/serviceconfig"
|
"google.golang.org/grpc/serviceconfig"
|
||||||
xdsinternal "google.golang.org/grpc/xds/internal"
|
|
||||||
"google.golang.org/grpc/xds/internal/balancer/edsbalancer"
|
"google.golang.org/grpc/xds/internal/balancer/edsbalancer"
|
||||||
"google.golang.org/grpc/xds/internal/balancer/lrs"
|
"google.golang.org/grpc/xds/internal/balancer/lrs"
|
||||||
)
|
)
|
||||||
@ -89,7 +88,7 @@ func (b *xdsBalancerBuilder) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *xdsBalancerBuilder) ParseConfig(c json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
|
func (b *xdsBalancerBuilder) ParseConfig(c json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
|
||||||
var cfg xdsinternal.LBConfig
|
var cfg XDSConfig
|
||||||
if err := json.Unmarshal(c, &cfg); err != nil {
|
if err := json.Unmarshal(c, &cfg); err != nil {
|
||||||
return nil, fmt.Errorf("unable to unmarshal balancer config %s into xds config", string(c))
|
return nil, fmt.Errorf("unable to unmarshal balancer config %s into xds config", string(c))
|
||||||
}
|
}
|
||||||
@ -132,15 +131,15 @@ type xdsBalancer struct {
|
|||||||
timer *time.Timer
|
timer *time.Timer
|
||||||
noSubConnAlert <-chan struct{}
|
noSubConnAlert <-chan struct{}
|
||||||
|
|
||||||
client *client // may change when passed a different service config
|
client *client // may change when passed a different service config
|
||||||
config *xdsinternal.LBConfig // may change when passed a different service config
|
config *XDSConfig // may change when passed a different service config
|
||||||
xdsLB edsBalancerInterface
|
xdsLB edsBalancerInterface
|
||||||
fallbackLB balancer.Balancer
|
fallbackLB balancer.Balancer
|
||||||
fallbackInitData *resolver.State // may change when HandleResolved address is called
|
fallbackInitData *resolver.State // may change when HandleResolved address is called
|
||||||
loadStore lrs.Store
|
loadStore lrs.Store
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *xdsBalancer) startNewXDSClient(u *xdsinternal.LBConfig) {
|
func (x *xdsBalancer) startNewXDSClient(u *XDSConfig) {
|
||||||
// If the xdsBalancer is in startup stage, then we need to apply the startup timeout for the first
|
// If the xdsBalancer is in startup stage, then we need to apply the startup timeout for the first
|
||||||
// xdsClient to get a response from the traffic director.
|
// xdsClient to get a response from the traffic director.
|
||||||
if x.startup {
|
if x.startup {
|
||||||
@ -192,7 +191,7 @@ func (x *xdsBalancer) startNewXDSClient(u *xdsinternal.LBConfig) {
|
|||||||
prevClient.close()
|
prevClient.close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
x.client = newXDSClient(u.BalancerName, x.buildOpts, x.loadStore, newADS, loseContact, exitCleanup)
|
x.client = newXDSClient(u.BalancerName, u.EDSServiceName, x.buildOpts, x.loadStore, newADS, loseContact, exitCleanup)
|
||||||
go x.client.run()
|
go x.client.run()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -239,7 +238,7 @@ func (x *xdsBalancer) handleGRPCUpdate(update interface{}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *balancer.ClientConnState:
|
case *balancer.ClientConnState:
|
||||||
cfg, _ := u.BalancerConfig.(*xdsinternal.LBConfig)
|
cfg, _ := u.BalancerConfig.(*XDSConfig)
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
// service config parsing failed. should never happen.
|
// service config parsing failed. should never happen.
|
||||||
return
|
return
|
||||||
@ -248,6 +247,11 @@ func (x *xdsBalancer) handleGRPCUpdate(update interface{}) {
|
|||||||
var fallbackChanged bool
|
var fallbackChanged bool
|
||||||
// service config has been updated.
|
// service config has been updated.
|
||||||
if !reflect.DeepEqual(cfg, x.config) {
|
if !reflect.DeepEqual(cfg, x.config) {
|
||||||
|
// TODO: handle cfg.LrsLoadReportingServerName and remove log.
|
||||||
|
if cfg.LrsLoadReportingServerName != "" {
|
||||||
|
grpclog.Warningf("xds: lrsLoadReportingServerName is not empty, but is not handled")
|
||||||
|
}
|
||||||
|
|
||||||
if x.config == nil {
|
if x.config == nil {
|
||||||
// The first time we get config, we just need to start the xdsClient.
|
// The first time we get config, we just need to start the xdsClient.
|
||||||
x.startNewXDSClient(cfg)
|
x.startNewXDSClient(cfg)
|
||||||
@ -483,16 +487,16 @@ func (x *xdsBalancer) cancelFallbackAndSwitchEDSBalancerIfNecessary() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *xdsBalancer) buildFallBackBalancer(c *xdsinternal.LBConfig) {
|
func (x *xdsBalancer) buildFallBackBalancer(c *XDSConfig) {
|
||||||
if c.FallBackPolicy == nil {
|
if c.FallBackPolicy == nil {
|
||||||
x.buildFallBackBalancer(&xdsinternal.LBConfig{
|
x.buildFallBackBalancer(&XDSConfig{
|
||||||
FallBackPolicy: &xdsinternal.LoadBalancingConfig{
|
FallBackPolicy: &loadBalancingConfig{
|
||||||
Name: "round_robin",
|
Name: "round_robin",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// builder will always be non-nil, since when parse JSON into xdsinternal.LBConfig, we check whether the specified
|
// builder will always be non-nil, since when parse JSON into xdsinternal.XDSConfig, we check whether the specified
|
||||||
// balancer is registered or not.
|
// balancer is registered or not.
|
||||||
builder := balancer.Get(c.FallBackPolicy.Name)
|
builder := balancer.Get(c.FallBackPolicy.Name)
|
||||||
|
|
||||||
|
@ -213,9 +213,9 @@ func (c *client) adsCallAttempt() (firstRespReceived bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newXDSClient(balancerName string, opts balancer.BuildOptions, loadStore lrs.Store, newADS func(context.Context, proto.Message) error, loseContact func(ctx context.Context), exitCleanup func()) *client {
|
func newXDSClient(balancerName string, edsServiceName string, opts balancer.BuildOptions, loadStore lrs.Store, newADS func(context.Context, proto.Message) error, loseContact func(ctx context.Context), exitCleanup func()) *client {
|
||||||
c := &client{
|
c := &client{
|
||||||
serviceName: opts.Target.Endpoint,
|
serviceName: edsServiceName,
|
||||||
dialer: opts.Dialer,
|
dialer: opts.Dialer,
|
||||||
channelzParentID: opts.ChannelzParentID,
|
channelzParentID: opts.ChannelzParentID,
|
||||||
newADS: newADS,
|
newADS: newADS,
|
||||||
@ -225,6 +225,10 @@ func newXDSClient(balancerName string, opts balancer.BuildOptions, loadStore lrs
|
|||||||
loadStore: loadStore,
|
loadStore: loadStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.serviceName == "" {
|
||||||
|
c.serviceName = opts.Target.Endpoint
|
||||||
|
}
|
||||||
|
|
||||||
c.ctx, c.cancel = context.WithCancel(context.Background())
|
c.ctx, c.cancel = context.WithCancel(context.Background())
|
||||||
|
|
||||||
// It is possible that NewConfig returns a Config object with certain
|
// It is possible that NewConfig returns a Config object with certain
|
||||||
|
@ -43,8 +43,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testServiceName = "test/foo"
|
testServiceName = "test/foo"
|
||||||
testEDSReq = &xdspb.DiscoveryRequest{
|
testEDSServiceName = "test/service/eds"
|
||||||
|
testEDSReq = &xdspb.DiscoveryRequest{
|
||||||
TypeUrl: edsType,
|
TypeUrl: edsType,
|
||||||
ResourceNames: []string{testServiceName},
|
ResourceNames: []string{testServiceName},
|
||||||
}
|
}
|
||||||
@ -177,6 +178,7 @@ func newTestTrafficDirector() *testTrafficDirector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type testConfig struct {
|
type testConfig struct {
|
||||||
|
edsServiceName string
|
||||||
expectedRequests []*xdspb.DiscoveryRequest
|
expectedRequests []*xdspb.DiscoveryRequest
|
||||||
responsesToSend []*xdspb.DiscoveryResponse
|
responsesToSend []*xdspb.DiscoveryResponse
|
||||||
expectedADSResponses []proto.Message
|
expectedADSResponses []proto.Message
|
||||||
@ -208,11 +210,22 @@ func setupServer(t *testing.T) (addr string, td *testTrafficDirector, lrss *lrsS
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s) TestXdsClientResponseHandling(t *testing.T) {
|
func (s) TestXdsClientResponseHandling(t *testing.T) {
|
||||||
for _, test := range []*testConfig{{
|
for _, test := range []*testConfig{
|
||||||
expectedRequests: []*xdspb.DiscoveryRequest{testEDSReq},
|
{
|
||||||
responsesToSend: []*xdspb.DiscoveryResponse{testEDSResp},
|
expectedRequests: []*xdspb.DiscoveryRequest{testEDSReq},
|
||||||
expectedADSResponses: []proto.Message{testClusterLoadAssignment},
|
responsesToSend: []*xdspb.DiscoveryResponse{testEDSResp},
|
||||||
}} {
|
expectedADSResponses: []proto.Message{testClusterLoadAssignment},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
edsServiceName: testEDSServiceName,
|
||||||
|
expectedRequests: []*xdspb.DiscoveryRequest{{
|
||||||
|
TypeUrl: edsType,
|
||||||
|
ResourceNames: []string{testEDSServiceName},
|
||||||
|
}},
|
||||||
|
responsesToSend: []*xdspb.DiscoveryResponse{testEDSResp},
|
||||||
|
expectedADSResponses: []proto.Message{testClusterLoadAssignment},
|
||||||
|
},
|
||||||
|
} {
|
||||||
testXdsClientResponseHandling(t, test)
|
testXdsClientResponseHandling(t, test)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -225,7 +238,7 @@ func testXdsClientResponseHandling(t *testing.T, test *testConfig) {
|
|||||||
adsChan <- i
|
adsChan <- i
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
client := newXDSClient(addr, balancer.BuildOptions{Target: resolver.Target{Endpoint: testServiceName}}, nil, newADS, func(context.Context) {}, func() {})
|
client := newXDSClient(addr, test.edsServiceName, balancer.BuildOptions{Target: resolver.Target{Endpoint: testServiceName}}, nil, newADS, func(context.Context) {}, func() {})
|
||||||
defer client.close()
|
defer client.close()
|
||||||
go client.run()
|
go client.run()
|
||||||
|
|
||||||
@ -282,7 +295,7 @@ func testXdsClientLoseContactRemoteClose(t *testing.T, test *testConfig) {
|
|||||||
loseContactFunc := func(context.Context) {
|
loseContactFunc := func(context.Context) {
|
||||||
contactChan <- &loseContact{}
|
contactChan <- &loseContact{}
|
||||||
}
|
}
|
||||||
client := newXDSClient(addr, balancer.BuildOptions{Target: resolver.Target{Endpoint: testServiceName}}, nil, newADS, loseContactFunc, func() {})
|
client := newXDSClient(addr, test.edsServiceName, balancer.BuildOptions{Target: resolver.Target{Endpoint: testServiceName}}, nil, newADS, loseContactFunc, func() {})
|
||||||
defer client.close()
|
defer client.close()
|
||||||
go client.run()
|
go client.run()
|
||||||
|
|
||||||
@ -316,7 +329,7 @@ func testXdsClientLoseContactADSRelatedErrorOccur(t *testing.T, test *testConfig
|
|||||||
loseContactFunc := func(context.Context) {
|
loseContactFunc := func(context.Context) {
|
||||||
contactChan <- &loseContact{}
|
contactChan <- &loseContact{}
|
||||||
}
|
}
|
||||||
client := newXDSClient(addr, balancer.BuildOptions{Target: resolver.Target{Endpoint: testServiceName}}, nil, newADS, loseContactFunc, func() {})
|
client := newXDSClient(addr, test.edsServiceName, balancer.BuildOptions{Target: resolver.Target{Endpoint: testServiceName}}, nil, newADS, loseContactFunc, func() {})
|
||||||
defer client.close()
|
defer client.close()
|
||||||
go client.run()
|
go client.run()
|
||||||
|
|
||||||
@ -350,7 +363,7 @@ func (s) TestXdsClientExponentialRetry(t *testing.T) {
|
|||||||
loseContactFunc := func(context.Context) {
|
loseContactFunc := func(context.Context) {
|
||||||
contactChan <- &loseContact{}
|
contactChan <- &loseContact{}
|
||||||
}
|
}
|
||||||
client := newXDSClient(addr, balancer.BuildOptions{Target: resolver.Target{Endpoint: testServiceName}}, nil, newADS, loseContactFunc, func() {})
|
client := newXDSClient(addr, "", balancer.BuildOptions{Target: resolver.Target{Endpoint: testServiceName}}, nil, newADS, loseContactFunc, func() {})
|
||||||
defer client.close()
|
defer client.close()
|
||||||
go client.run()
|
go client.run()
|
||||||
|
|
||||||
|
@ -34,7 +34,6 @@ import (
|
|||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/resolver"
|
"google.golang.org/grpc/resolver"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
xdsinternal "google.golang.org/grpc/xds/internal"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type lrsServer struct {
|
type lrsServer struct {
|
||||||
@ -105,7 +104,7 @@ func (s) TestXdsLoadReporting(t *testing.T) {
|
|||||||
Nanos: intervalNano,
|
Nanos: intervalNano,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := &xdsinternal.LBConfig{
|
cfg := &XDSConfig{
|
||||||
BalancerName: addr,
|
BalancerName: addr,
|
||||||
}
|
}
|
||||||
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: cfg})
|
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: cfg})
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package balancer
|
package balancer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sync"
|
"sync"
|
||||||
@ -26,13 +27,17 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
xdspb "github.com/envoyproxy/go-control-plane/envoy/api/v2"
|
xdspb "github.com/envoyproxy/go-control-plane/envoy/api/v2"
|
||||||
|
"github.com/golang/protobuf/jsonpb"
|
||||||
"github.com/golang/protobuf/proto"
|
"github.com/golang/protobuf/proto"
|
||||||
|
wrapperspb "github.com/golang/protobuf/ptypes/wrappers"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
"google.golang.org/grpc/balancer"
|
"google.golang.org/grpc/balancer"
|
||||||
"google.golang.org/grpc/connectivity"
|
"google.golang.org/grpc/connectivity"
|
||||||
"google.golang.org/grpc/internal/grpctest"
|
"google.golang.org/grpc/internal/grpctest"
|
||||||
"google.golang.org/grpc/internal/leakcheck"
|
"google.golang.org/grpc/internal/leakcheck"
|
||||||
|
scpb "google.golang.org/grpc/internal/proto/grpc_service_config"
|
||||||
"google.golang.org/grpc/resolver"
|
"google.golang.org/grpc/resolver"
|
||||||
xdsinternal "google.golang.org/grpc/xds/internal"
|
"google.golang.org/grpc/serviceconfig"
|
||||||
"google.golang.org/grpc/xds/internal/balancer/lrs"
|
"google.golang.org/grpc/xds/internal/balancer/lrs"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -61,10 +66,10 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
testBalancerNameFooBar = "foo.bar"
|
testBalancerNameFooBar = "foo.bar"
|
||||||
testLBConfigFooBar = &xdsinternal.LBConfig{
|
testLBConfigFooBar = &XDSConfig{
|
||||||
BalancerName: testBalancerNameFooBar,
|
BalancerName: testBalancerNameFooBar,
|
||||||
ChildPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerB},
|
ChildPolicy: &loadBalancingConfig{Name: fakeBalancerB},
|
||||||
FallBackPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
FallBackPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
||||||
}
|
}
|
||||||
|
|
||||||
specialAddrForBalancerA = resolver.Address{Addr: "this.is.balancer.A"}
|
specialAddrForBalancerA = resolver.Address{Addr: "this.is.balancer.A"}
|
||||||
@ -174,8 +179,8 @@ type scStateChange struct {
|
|||||||
type fakeEDSBalancer struct {
|
type fakeEDSBalancer struct {
|
||||||
cc balancer.ClientConn
|
cc balancer.ClientConn
|
||||||
edsChan chan *xdspb.ClusterLoadAssignment
|
edsChan chan *xdspb.ClusterLoadAssignment
|
||||||
childPolicy chan *xdsinternal.LoadBalancingConfig
|
childPolicy chan *loadBalancingConfig
|
||||||
fallbackPolicy chan *xdsinternal.LoadBalancingConfig
|
fallbackPolicy chan *loadBalancingConfig
|
||||||
subconnStateChange chan *scStateChange
|
subconnStateChange chan *scStateChange
|
||||||
loadStore lrs.Store
|
loadStore lrs.Store
|
||||||
}
|
}
|
||||||
@ -195,7 +200,7 @@ func (f *fakeEDSBalancer) HandleEDSResponse(edsResp *xdspb.ClusterLoadAssignment
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeEDSBalancer) HandleChildPolicy(name string, config json.RawMessage) {
|
func (f *fakeEDSBalancer) HandleChildPolicy(name string, config json.RawMessage) {
|
||||||
f.childPolicy <- &xdsinternal.LoadBalancingConfig{
|
f.childPolicy <- &loadBalancingConfig{
|
||||||
Name: name,
|
Name: name,
|
||||||
Config: config,
|
Config: config,
|
||||||
}
|
}
|
||||||
@ -205,8 +210,8 @@ func newFakeEDSBalancer(cc balancer.ClientConn, loadStore lrs.Store) edsBalancer
|
|||||||
lb := &fakeEDSBalancer{
|
lb := &fakeEDSBalancer{
|
||||||
cc: cc,
|
cc: cc,
|
||||||
edsChan: make(chan *xdspb.ClusterLoadAssignment, 10),
|
edsChan: make(chan *xdspb.ClusterLoadAssignment, 10),
|
||||||
childPolicy: make(chan *xdsinternal.LoadBalancingConfig, 10),
|
childPolicy: make(chan *loadBalancingConfig, 10),
|
||||||
fallbackPolicy: make(chan *xdsinternal.LoadBalancingConfig, 10),
|
fallbackPolicy: make(chan *loadBalancingConfig, 10),
|
||||||
subconnStateChange: make(chan *scStateChange, 10),
|
subconnStateChange: make(chan *scStateChange, 10),
|
||||||
loadStore: loadStore,
|
loadStore: loadStore,
|
||||||
}
|
}
|
||||||
@ -328,10 +333,10 @@ func (s) TestXdsBalanceHandleBalancerConfigBalancerNameUpdate(t *testing.T) {
|
|||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
addr, td, _, cleanup := setupServer(t)
|
addr, td, _, cleanup := setupServer(t)
|
||||||
cleanups = append(cleanups, cleanup)
|
cleanups = append(cleanups, cleanup)
|
||||||
workingLBConfig := &xdsinternal.LBConfig{
|
workingLBConfig := &XDSConfig{
|
||||||
BalancerName: addr,
|
BalancerName: addr,
|
||||||
ChildPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
ChildPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
||||||
FallBackPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
FallBackPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
||||||
}
|
}
|
||||||
lb.UpdateClientConnState(balancer.ClientConnState{
|
lb.UpdateClientConnState(balancer.ClientConnState{
|
||||||
ResolverState: resolver.State{Addresses: addrs},
|
ResolverState: resolver.State{Addresses: addrs},
|
||||||
@ -383,31 +388,31 @@ func (s) TestXdsBalanceHandleBalancerConfigChildPolicyUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
cfg *xdsinternal.LBConfig
|
cfg *XDSConfig
|
||||||
responseToSend *xdspb.DiscoveryResponse
|
responseToSend *xdspb.DiscoveryResponse
|
||||||
expectedChildPolicy *xdsinternal.LoadBalancingConfig
|
expectedChildPolicy *loadBalancingConfig
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
cfg: &xdsinternal.LBConfig{
|
cfg: &XDSConfig{
|
||||||
ChildPolicy: &xdsinternal.LoadBalancingConfig{
|
ChildPolicy: &loadBalancingConfig{
|
||||||
Name: fakeBalancerA,
|
Name: fakeBalancerA,
|
||||||
Config: json.RawMessage("{}"),
|
Config: json.RawMessage("{}"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
responseToSend: testEDSResp,
|
responseToSend: testEDSResp,
|
||||||
expectedChildPolicy: &xdsinternal.LoadBalancingConfig{
|
expectedChildPolicy: &loadBalancingConfig{
|
||||||
Name: string(fakeBalancerA),
|
Name: string(fakeBalancerA),
|
||||||
Config: json.RawMessage(`{}`),
|
Config: json.RawMessage(`{}`),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cfg: &xdsinternal.LBConfig{
|
cfg: &XDSConfig{
|
||||||
ChildPolicy: &xdsinternal.LoadBalancingConfig{
|
ChildPolicy: &loadBalancingConfig{
|
||||||
Name: fakeBalancerB,
|
Name: fakeBalancerB,
|
||||||
Config: json.RawMessage("{}"),
|
Config: json.RawMessage("{}"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedChildPolicy: &xdsinternal.LoadBalancingConfig{
|
expectedChildPolicy: &loadBalancingConfig{
|
||||||
Name: string(fakeBalancerB),
|
Name: string(fakeBalancerB),
|
||||||
Config: json.RawMessage(`{}`),
|
Config: json.RawMessage(`{}`),
|
||||||
},
|
},
|
||||||
@ -461,16 +466,16 @@ func (s) TestXdsBalanceHandleBalancerConfigFallBackUpdate(t *testing.T) {
|
|||||||
|
|
||||||
addr, td, _, cleanup := setupServer(t)
|
addr, td, _, cleanup := setupServer(t)
|
||||||
|
|
||||||
cfg := xdsinternal.LBConfig{
|
cfg := XDSConfig{
|
||||||
BalancerName: addr,
|
BalancerName: addr,
|
||||||
ChildPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
ChildPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
||||||
FallBackPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
FallBackPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
||||||
}
|
}
|
||||||
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: &cfg})
|
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: &cfg})
|
||||||
|
|
||||||
addrs := []resolver.Address{{Addr: "1.1.1.1:10001"}, {Addr: "2.2.2.2:10002"}, {Addr: "3.3.3.3:10003"}}
|
addrs := []resolver.Address{{Addr: "1.1.1.1:10001"}, {Addr: "2.2.2.2:10002"}, {Addr: "3.3.3.3:10003"}}
|
||||||
cfg2 := cfg
|
cfg2 := cfg
|
||||||
cfg2.FallBackPolicy = &xdsinternal.LoadBalancingConfig{Name: fakeBalancerB}
|
cfg2.FallBackPolicy = &loadBalancingConfig{Name: fakeBalancerB}
|
||||||
lb.UpdateClientConnState(balancer.ClientConnState{
|
lb.UpdateClientConnState(balancer.ClientConnState{
|
||||||
ResolverState: resolver.State{Addresses: addrs},
|
ResolverState: resolver.State{Addresses: addrs},
|
||||||
BalancerConfig: &cfg2,
|
BalancerConfig: &cfg2,
|
||||||
@ -502,7 +507,7 @@ func (s) TestXdsBalanceHandleBalancerConfigFallBackUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cfg3 := cfg
|
cfg3 := cfg
|
||||||
cfg3.FallBackPolicy = &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA}
|
cfg3.FallBackPolicy = &loadBalancingConfig{Name: fakeBalancerA}
|
||||||
lb.UpdateClientConnState(balancer.ClientConnState{
|
lb.UpdateClientConnState(balancer.ClientConnState{
|
||||||
ResolverState: resolver.State{Addresses: addrs},
|
ResolverState: resolver.State{Addresses: addrs},
|
||||||
BalancerConfig: &cfg3,
|
BalancerConfig: &cfg3,
|
||||||
@ -536,10 +541,10 @@ func (s) TestXdsBalancerHandlerSubConnStateChange(t *testing.T) {
|
|||||||
|
|
||||||
addr, td, _, cleanup := setupServer(t)
|
addr, td, _, cleanup := setupServer(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
cfg := &xdsinternal.LBConfig{
|
cfg := &XDSConfig{
|
||||||
BalancerName: addr,
|
BalancerName: addr,
|
||||||
ChildPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
ChildPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
||||||
FallBackPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
FallBackPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
||||||
}
|
}
|
||||||
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: cfg})
|
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: cfg})
|
||||||
|
|
||||||
@ -614,10 +619,10 @@ func (s) TestXdsBalancerFallBackSignalFromEdsBalancer(t *testing.T) {
|
|||||||
|
|
||||||
addr, td, _, cleanup := setupServer(t)
|
addr, td, _, cleanup := setupServer(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
cfg := &xdsinternal.LBConfig{
|
cfg := &XDSConfig{
|
||||||
BalancerName: addr,
|
BalancerName: addr,
|
||||||
ChildPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
ChildPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
||||||
FallBackPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
FallBackPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
||||||
}
|
}
|
||||||
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: cfg})
|
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: cfg})
|
||||||
|
|
||||||
@ -675,43 +680,119 @@ func (s) TestXdsBalancerFallBackSignalFromEdsBalancer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s) TestXdsBalancerConfigParsingSelectingLBPolicy(t *testing.T) {
|
func TestXdsBalancerConfigParsing(t *testing.T) {
|
||||||
js := json.RawMessage(`{
|
const (
|
||||||
"balancerName": "fake.foo.bar",
|
testEDSName = "eds.service"
|
||||||
"childPolicy": [{"fake_balancer_C": {}}, {"fake_balancer_A": {}}, {"fake_balancer_B": {}}],
|
testLRSName = "lrs.server"
|
||||||
"fallbackPolicy": [{"fake_balancer_C": {}}, {"fake_balancer_B": {}}, {"fake_balancer_A": {}}]
|
)
|
||||||
}`)
|
b := bytes.NewBuffer(nil)
|
||||||
cfg, err := (&xdsBalancerBuilder{}).ParseConfig(js)
|
if err := (&jsonpb.Marshaler{}).Marshal(b, &scpb.XdsConfig{
|
||||||
if err != nil {
|
ChildPolicy: []*scpb.LoadBalancingConfig{
|
||||||
t.Fatalf("unable to unmarshal balancer config into xds config: %v", err)
|
{Policy: &scpb.LoadBalancingConfig_Xds{}},
|
||||||
|
{Policy: &scpb.LoadBalancingConfig_RoundRobin{
|
||||||
|
RoundRobin: &scpb.RoundRobinConfig{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
FallbackPolicy: []*scpb.LoadBalancingConfig{
|
||||||
|
{Policy: &scpb.LoadBalancingConfig_Xds{}},
|
||||||
|
{Policy: &scpb.LoadBalancingConfig_PickFirst{
|
||||||
|
PickFirst: &scpb.PickFirstConfig{},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
EdsServiceName: testEDSName,
|
||||||
|
LrsLoadReportingServerName: &wrapperspb.StringValue{Value: testLRSName},
|
||||||
|
}); err != nil {
|
||||||
|
t.Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
xdsCfg := cfg.(*xdsinternal.LBConfig)
|
|
||||||
wantChildPolicy := &xdsinternal.LoadBalancingConfig{Name: string(fakeBalancerA), Config: json.RawMessage(`{}`)}
|
tests := []struct {
|
||||||
if !reflect.DeepEqual(xdsCfg.ChildPolicy, wantChildPolicy) {
|
name string
|
||||||
t.Fatalf("got child policy %v, want %v", xdsCfg.ChildPolicy, wantChildPolicy)
|
js json.RawMessage
|
||||||
|
want serviceconfig.LoadBalancingConfig
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "jsonpb-generated",
|
||||||
|
js: b.Bytes(),
|
||||||
|
want: &XDSConfig{
|
||||||
|
ChildPolicy: &loadBalancingConfig{
|
||||||
|
Name: "round_robin",
|
||||||
|
Config: json.RawMessage("{}"),
|
||||||
|
},
|
||||||
|
FallBackPolicy: &loadBalancingConfig{
|
||||||
|
Name: "pick_first",
|
||||||
|
Config: json.RawMessage("{}"),
|
||||||
|
},
|
||||||
|
EDSServiceName: testEDSName,
|
||||||
|
LrsLoadReportingServerName: testLRSName,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// json with random balancers, and the first is not registered.
|
||||||
|
name: "manually-generated",
|
||||||
|
js: json.RawMessage(`
|
||||||
|
{
|
||||||
|
"balancerName": "fake.foo.bar",
|
||||||
|
"childPolicy": [
|
||||||
|
{"fake_balancer_C": {}},
|
||||||
|
{"fake_balancer_A": {}},
|
||||||
|
{"fake_balancer_B": {}}
|
||||||
|
],
|
||||||
|
"fallbackPolicy": [
|
||||||
|
{"fake_balancer_C": {}},
|
||||||
|
{"fake_balancer_B": {}},
|
||||||
|
{"fake_balancer_A": {}}
|
||||||
|
],
|
||||||
|
"edsServiceName": "eds.service",
|
||||||
|
"lrsLoadReportingServerName": "lrs.server"
|
||||||
|
}`),
|
||||||
|
want: &XDSConfig{
|
||||||
|
BalancerName: "fake.foo.bar",
|
||||||
|
ChildPolicy: &loadBalancingConfig{
|
||||||
|
Name: "fake_balancer_A",
|
||||||
|
Config: json.RawMessage("{}"),
|
||||||
|
},
|
||||||
|
FallBackPolicy: &loadBalancingConfig{
|
||||||
|
Name: "fake_balancer_B",
|
||||||
|
Config: json.RawMessage("{}"),
|
||||||
|
},
|
||||||
|
EDSServiceName: testEDSName,
|
||||||
|
LrsLoadReportingServerName: testLRSName,
|
||||||
|
},
|
||||||
|
wantErr: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
wantFallbackPolicy := &xdsinternal.LoadBalancingConfig{Name: string(fakeBalancerB), Config: json.RawMessage(`{}`)}
|
for _, tt := range tests {
|
||||||
if !reflect.DeepEqual(xdsCfg.FallBackPolicy, wantFallbackPolicy) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
t.Fatalf("got fallback policy %v, want %v", xdsCfg.FallBackPolicy, wantFallbackPolicy)
|
b := &xdsBalancerBuilder{}
|
||||||
|
got, err := b.ParseConfig(tt.js)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("xdsBalancerBuilder.ParseConfig() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !cmp.Equal(got, tt.want) {
|
||||||
|
t.Errorf(cmp.Diff(got, tt.want))
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
func TestLoadbalancingConfigParsing(t *testing.T) {
|
||||||
func (s) TestXdsLoadbalancingConfigParsing(t *testing.T) {
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
s string
|
s string
|
||||||
want *xdsinternal.LBConfig
|
want *XDSConfig
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty",
|
name: "empty",
|
||||||
s: "{}",
|
s: "{}",
|
||||||
want: &xdsinternal.LBConfig{},
|
want: &XDSConfig{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "success1",
|
name: "success1",
|
||||||
s: `{"childPolicy":[{"pick_first":{}}]}`,
|
s: `{"childPolicy":[{"pick_first":{}}]}`,
|
||||||
want: &xdsinternal.LBConfig{
|
want: &XDSConfig{
|
||||||
ChildPolicy: &xdsinternal.LoadBalancingConfig{
|
ChildPolicy: &loadBalancingConfig{
|
||||||
Name: "pick_first",
|
Name: "pick_first",
|
||||||
Config: json.RawMessage(`{}`),
|
Config: json.RawMessage(`{}`),
|
||||||
},
|
},
|
||||||
@ -720,8 +801,8 @@ func (s) TestXdsLoadbalancingConfigParsing(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "success2",
|
name: "success2",
|
||||||
s: `{"childPolicy":[{"round_robin":{}},{"pick_first":{}}]}`,
|
s: `{"childPolicy":[{"round_robin":{}},{"pick_first":{}}]}`,
|
||||||
want: &xdsinternal.LBConfig{
|
want: &XDSConfig{
|
||||||
ChildPolicy: &xdsinternal.LoadBalancingConfig{
|
ChildPolicy: &loadBalancingConfig{
|
||||||
Name: "round_robin",
|
Name: "round_robin",
|
||||||
Config: json.RawMessage(`{}`),
|
Config: json.RawMessage(`{}`),
|
||||||
},
|
},
|
||||||
@ -730,7 +811,7 @@ func (s) TestXdsLoadbalancingConfigParsing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
var cfg xdsinternal.LBConfig
|
var cfg XDSConfig
|
||||||
if err := json.Unmarshal([]byte(tt.s), &cfg); err != nil || !reflect.DeepEqual(&cfg, tt.want) {
|
if err := json.Unmarshal([]byte(tt.s), &cfg); err != nil || !reflect.DeepEqual(&cfg, tt.want) {
|
||||||
t.Errorf("test name: %s, parseFullServiceConfig() = %+v, err: %v, want %+v, <nil>", tt.name, cfg, err, tt.want)
|
t.Errorf("test name: %s, parseFullServiceConfig() = %+v, err: %v, want %+v, <nil>", tt.name, cfg, err, tt.want)
|
||||||
}
|
}
|
||||||
|
@ -18,12 +18,9 @@
|
|||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
|
corepb "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
|
||||||
"google.golang.org/grpc/balancer"
|
|
||||||
"google.golang.org/grpc/serviceconfig"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Locality is xds.Locality without XXX fields, so it can be used as map
|
// Locality is xds.Locality without XXX fields, so it can be used as map
|
||||||
@ -51,88 +48,3 @@ func (lamk Locality) ToProto() *corepb.Locality {
|
|||||||
SubZone: lamk.SubZone,
|
SubZone: lamk.SubZone,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// LBConfig represents the loadBalancingConfig section of the service config
|
|
||||||
// for xDS balancers.
|
|
||||||
type LBConfig struct {
|
|
||||||
serviceconfig.LoadBalancingConfig
|
|
||||||
// BalancerName represents the load balancer to use.
|
|
||||||
BalancerName string
|
|
||||||
// ChildPolicy represents the load balancing config for the child policy.
|
|
||||||
ChildPolicy *LoadBalancingConfig
|
|
||||||
// FallBackPolicy represents the load balancing config for the fallback.
|
|
||||||
FallBackPolicy *LoadBalancingConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON parses the JSON-encoded byte slice in data and stores it in l.
|
|
||||||
// When unmarshalling, we iterate through the childPolicy/fallbackPolicy lists
|
|
||||||
// and select the first LB policy which has been registered.
|
|
||||||
func (l *LBConfig) UnmarshalJSON(data []byte) error {
|
|
||||||
var val map[string]json.RawMessage
|
|
||||||
if err := json.Unmarshal(data, &val); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for k, v := range val {
|
|
||||||
switch k {
|
|
||||||
case "balancerName":
|
|
||||||
if err := json.Unmarshal(v, &l.BalancerName); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case "childPolicy":
|
|
||||||
var lbcfgs []*LoadBalancingConfig
|
|
||||||
if err := json.Unmarshal(v, &lbcfgs); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, lbcfg := range lbcfgs {
|
|
||||||
if balancer.Get(lbcfg.Name) != nil {
|
|
||||||
l.ChildPolicy = lbcfg
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "fallbackPolicy":
|
|
||||||
var lbcfgs []*LoadBalancingConfig
|
|
||||||
if err := json.Unmarshal(v, &lbcfgs); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for _, lbcfg := range lbcfgs {
|
|
||||||
if balancer.Get(lbcfg.Name) != nil {
|
|
||||||
l.FallBackPolicy = lbcfg
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON returns a JSON encoding of l.
|
|
||||||
func (l *LBConfig) MarshalJSON() ([]byte, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadBalancingConfig represents a single load balancing config,
|
|
||||||
// stored in JSON format.
|
|
||||||
type LoadBalancingConfig struct {
|
|
||||||
Name string
|
|
||||||
Config json.RawMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON returns a JSON encoding of l.
|
|
||||||
func (l *LoadBalancingConfig) MarshalJSON() ([]byte, error) {
|
|
||||||
m := make(map[string]json.RawMessage)
|
|
||||||
m[l.Name] = l.Config
|
|
||||||
return json.Marshal(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON parses the JSON-encoded byte slice in data and stores it in l.
|
|
||||||
func (l *LoadBalancingConfig) UnmarshalJSON(data []byte) error {
|
|
||||||
var cfg map[string]json.RawMessage
|
|
||||||
if err := json.Unmarshal(data, &cfg); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
for name, config := range cfg {
|
|
||||||
l.Name = name
|
|
||||||
l.Config = config
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -31,7 +31,7 @@ import (
|
|||||||
"google.golang.org/grpc/internal"
|
"google.golang.org/grpc/internal"
|
||||||
"google.golang.org/grpc/resolver"
|
"google.golang.org/grpc/resolver"
|
||||||
"google.golang.org/grpc/serviceconfig"
|
"google.golang.org/grpc/serviceconfig"
|
||||||
xdsinternal "google.golang.org/grpc/xds/internal"
|
xdsbalancer "google.golang.org/grpc/xds/internal/balancer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This is initialized at init time.
|
// This is initialized at init time.
|
||||||
@ -118,7 +118,7 @@ func (*fakeBalancer) ResolverError(error) {
|
|||||||
panic("unimplemented")
|
panic("unimplemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateClientConnState verifies that the received LBConfig matches the
|
// UpdateClientConnState verifies that the received edsConfig matches the
|
||||||
// provided one, and if not, sends an error on the provided channel.
|
// provided one, and if not, sends an error on the provided channel.
|
||||||
func (f *fakeBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error {
|
func (f *fakeBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error {
|
||||||
gotLBConfig, ok := ccs.BalancerConfig.(*wrappedLBConfig)
|
gotLBConfig, ok := ccs.BalancerConfig.(*wrappedLBConfig)
|
||||||
@ -127,7 +127,7 @@ func (f *fakeBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error
|
|||||||
return balancer.ErrBadResolverState
|
return balancer.ErrBadResolverState
|
||||||
}
|
}
|
||||||
|
|
||||||
var gotCfg, wantCfg xdsinternal.LBConfig
|
var gotCfg, wantCfg xdsbalancer.XDSConfig
|
||||||
if err := wantCfg.UnmarshalJSON(f.wantLBConfig.lbCfg); err != nil {
|
if err := wantCfg.UnmarshalJSON(f.wantLBConfig.lbCfg); err != nil {
|
||||||
f.errCh <- fmt.Errorf("unable to unmarshal balancer config %s into xds config", string(f.wantLBConfig.lbCfg))
|
f.errCh <- fmt.Errorf("unable to unmarshal balancer config %s into xds config", string(f.wantLBConfig.lbCfg))
|
||||||
return balancer.ErrBadResolverState
|
return balancer.ErrBadResolverState
|
||||||
@ -136,6 +136,7 @@ func (f *fakeBalancer) UpdateClientConnState(ccs balancer.ClientConnState) error
|
|||||||
f.errCh <- fmt.Errorf("unable to unmarshal balancer config %s into xds config", string(gotLBConfig.lbCfg))
|
f.errCh <- fmt.Errorf("unable to unmarshal balancer config %s into xds config", string(gotLBConfig.lbCfg))
|
||||||
return balancer.ErrBadResolverState
|
return balancer.ErrBadResolverState
|
||||||
}
|
}
|
||||||
|
|
||||||
if !reflect.DeepEqual(gotCfg, wantCfg) {
|
if !reflect.DeepEqual(gotCfg, wantCfg) {
|
||||||
f.errCh <- fmt.Errorf("in fakeBalancer got lbConfig %v, want %v", gotCfg, wantCfg)
|
f.errCh <- fmt.Errorf("in fakeBalancer got lbConfig %v, want %v", gotCfg, wantCfg)
|
||||||
return balancer.ErrBadResolverState
|
return balancer.ErrBadResolverState
|
||||||
@ -171,7 +172,7 @@ func (f *fakeBalancerBuilder) ParseConfig(c json.RawMessage) (serviceconfig.Load
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wrappedLBConfig simply wraps the provided LB config with a
|
// wrappedLBConfig simply wraps the provided LB config with a
|
||||||
// serviceconfig.LoadBalancingConfig interface.
|
// serviceconfig.loadBalancingConfig interface.
|
||||||
type wrappedLBConfig struct {
|
type wrappedLBConfig struct {
|
||||||
serviceconfig.LoadBalancingConfig
|
serviceconfig.LoadBalancingConfig
|
||||||
lbCfg json.RawMessage
|
lbCfg json.RawMessage
|
||||||
|
Reference in New Issue
Block a user