mirror of https://github.com/grpc/grpc-go.git
Implementation of the xds_experimental resolver. (#2967)
This resolver doesn't do much at this point, except returning an empty address list and a hard-coded service config which picks the xds balancer with a round_robin child policy. Also moved the xdsConfig struct to the xds/internal package and exported it as LBConfig, so that both the resolver and the balancer packages can make use of this.
This commit is contained in:
parent
3bb34e5324
commit
dc1875474e
1
vet.sh
1
vet.sh
|
|
@ -111,6 +111,7 @@ google.golang.org/grpc/balancer.go:SA1019
|
||||||
google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go:SA1019
|
google.golang.org/grpc/balancer/grpclb/grpclb_remote_balancer.go:SA1019
|
||||||
google.golang.org/grpc/balancer/roundrobin/roundrobin_test.go:SA1019
|
google.golang.org/grpc/balancer/roundrobin/roundrobin_test.go:SA1019
|
||||||
google.golang.org/grpc/xds/internal/balancer/edsbalancer/balancergroup.go:SA1019
|
google.golang.org/grpc/xds/internal/balancer/edsbalancer/balancergroup.go:SA1019
|
||||||
|
google.golang.org/grpc/xds/internal/resolver/xds_resolver.go:SA1019
|
||||||
google.golang.org/grpc/xds/internal/balancer/xds.go:SA1019
|
google.golang.org/grpc/xds/internal/balancer/xds.go:SA1019
|
||||||
google.golang.org/grpc/xds/internal/balancer/xds_client.go:SA1019
|
google.golang.org/grpc/xds/internal/balancer/xds_client.go:SA1019
|
||||||
google.golang.org/grpc/balancer_conn_wrappers.go:SA1019
|
google.golang.org/grpc/balancer_conn_wrappers.go:SA1019
|
||||||
|
|
|
||||||
|
|
@ -24,9 +24,12 @@ package experimental
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"google.golang.org/grpc/balancer"
|
"google.golang.org/grpc/balancer"
|
||||||
|
"google.golang.org/grpc/resolver"
|
||||||
xdsbalancer "google.golang.org/grpc/xds/internal/balancer"
|
xdsbalancer "google.golang.org/grpc/xds/internal/balancer"
|
||||||
|
xdsresolver "google.golang.org/grpc/xds/internal/resolver"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
resolver.Register(xdsresolver.NewBuilder())
|
||||||
balancer.Register(xdsbalancer.NewBalancerBuilder())
|
balancer.Register(xdsbalancer.NewBalancerBuilder())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ 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"
|
||||||
cdspb "google.golang.org/grpc/xds/internal/proto/envoy/api/v2/cds"
|
cdspb "google.golang.org/grpc/xds/internal/proto/envoy/api/v2/cds"
|
||||||
|
|
@ -89,7 +90,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 xdsConfig
|
var cfg xdsinternal.LBConfig
|
||||||
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))
|
||||||
}
|
}
|
||||||
|
|
@ -131,14 +132,14 @@ type xdsBalancer struct {
|
||||||
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 *xdsConfig // may change when passed a different service config
|
config *xdsinternal.LBConfig // 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 *xdsConfig) {
|
func (x *xdsBalancer) startNewXDSClient(u *xdsinternal.LBConfig) {
|
||||||
// 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 {
|
||||||
|
|
@ -237,7 +238,7 @@ func (x *xdsBalancer) handleGRPCUpdate(update interface{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *balancer.ClientConnState:
|
case *balancer.ClientConnState:
|
||||||
cfg, _ := u.BalancerConfig.(*xdsConfig)
|
cfg, _ := u.BalancerConfig.(*xdsinternal.LBConfig)
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
// service config parsing failed. should never happen.
|
// service config parsing failed. should never happen.
|
||||||
return
|
return
|
||||||
|
|
@ -497,16 +498,16 @@ func (x *xdsBalancer) cancelFallbackAndSwitchEDSBalancerIfNecessary() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (x *xdsBalancer) buildFallBackBalancer(c *xdsConfig) {
|
func (x *xdsBalancer) buildFallBackBalancer(c *xdsinternal.LBConfig) {
|
||||||
if c.FallBackPolicy == nil {
|
if c.FallBackPolicy == nil {
|
||||||
x.buildFallBackBalancer(&xdsConfig{
|
x.buildFallBackBalancer(&xdsinternal.LBConfig{
|
||||||
FallBackPolicy: &loadBalancingConfig{
|
FallBackPolicy: &xdsinternal.LoadBalancingConfig{
|
||||||
Name: "round_robin",
|
Name: "round_robin",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// builder will always be non-nil, since when parse JSON into xdsConfig, we check whether the specified
|
// builder will always be non-nil, since when parse JSON into xdsinternal.LBConfig, 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)
|
||||||
|
|
||||||
|
|
@ -566,77 +567,3 @@ func createDrainedTimer() *time.Timer {
|
||||||
}
|
}
|
||||||
return timer
|
return timer
|
||||||
}
|
}
|
||||||
|
|
||||||
type xdsConfig struct {
|
|
||||||
serviceconfig.LoadBalancingConfig
|
|
||||||
BalancerName string
|
|
||||||
ChildPolicy *loadBalancingConfig
|
|
||||||
FallBackPolicy *loadBalancingConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// When unmarshalling json to xdsConfig, we iterate through the childPolicy/fallbackPolicy lists
|
|
||||||
// and select the first LB policy which has been registered to be stored in the returned xdsConfig.
|
|
||||||
func (p *xdsConfig) 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, &p.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 {
|
|
||||||
p.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 {
|
|
||||||
p.FallBackPolicy = lbcfg
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *xdsConfig) MarshalJSON() ([]byte, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type loadBalancingConfig struct {
|
|
||||||
Name string
|
|
||||||
Config json.RawMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *loadBalancingConfig) MarshalJSON() ([]byte, error) {
|
|
||||||
m := make(map[string]json.RawMessage)
|
|
||||||
m[l.Name] = l.Config
|
|
||||||
return json.Marshal(m)
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import (
|
||||||
"google.golang.org/grpc/resolver"
|
"google.golang.org/grpc/resolver"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
"google.golang.org/grpc/xds/internal"
|
"google.golang.org/grpc/xds/internal"
|
||||||
|
xdsinternal "google.golang.org/grpc/xds/internal"
|
||||||
basepb "google.golang.org/grpc/xds/internal/proto/envoy/api/v2/core/base"
|
basepb "google.golang.org/grpc/xds/internal/proto/envoy/api/v2/core/base"
|
||||||
lrsgrpc "google.golang.org/grpc/xds/internal/proto/envoy/service/load_stats/v2/lrs"
|
lrsgrpc "google.golang.org/grpc/xds/internal/proto/envoy/service/load_stats/v2/lrs"
|
||||||
lrspb "google.golang.org/grpc/xds/internal/proto/envoy/service/load_stats/v2/lrs"
|
lrspb "google.golang.org/grpc/xds/internal/proto/envoy/service/load_stats/v2/lrs"
|
||||||
|
|
@ -112,9 +113,9 @@ func (s) TestXdsLoadReporting(t *testing.T) {
|
||||||
Nanos: intervalNano,
|
Nanos: intervalNano,
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := &xdsConfig{
|
cfg := &xdsinternal.LBConfig{
|
||||||
BalancerName: addr,
|
BalancerName: addr,
|
||||||
ChildPolicy: &loadBalancingConfig{Name: fakeBalancerA}, // Set this to skip cds.
|
ChildPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA}, // Set this to skip cds.
|
||||||
}
|
}
|
||||||
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: cfg})
|
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: cfg})
|
||||||
td.sendResp(&response{resp: testEDSRespWithoutEndpoints})
|
td.sendResp(&response{resp: testEDSRespWithoutEndpoints})
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"google.golang.org/grpc/internal/grpctest"
|
"google.golang.org/grpc/internal/grpctest"
|
||||||
"google.golang.org/grpc/internal/leakcheck"
|
"google.golang.org/grpc/internal/leakcheck"
|
||||||
"google.golang.org/grpc/resolver"
|
"google.golang.org/grpc/resolver"
|
||||||
|
xdsinternal "google.golang.org/grpc/xds/internal"
|
||||||
"google.golang.org/grpc/xds/internal/balancer/lrs"
|
"google.golang.org/grpc/xds/internal/balancer/lrs"
|
||||||
discoverypb "google.golang.org/grpc/xds/internal/proto/envoy/api/v2/discovery"
|
discoverypb "google.golang.org/grpc/xds/internal/proto/envoy/api/v2/discovery"
|
||||||
edspb "google.golang.org/grpc/xds/internal/proto/envoy/api/v2/eds"
|
edspb "google.golang.org/grpc/xds/internal/proto/envoy/api/v2/eds"
|
||||||
|
|
@ -62,10 +63,10 @@ const (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
testBalancerNameFooBar = "foo.bar"
|
testBalancerNameFooBar = "foo.bar"
|
||||||
testLBConfigFooBar = &xdsConfig{
|
testLBConfigFooBar = &xdsinternal.LBConfig{
|
||||||
BalancerName: testBalancerNameFooBar,
|
BalancerName: testBalancerNameFooBar,
|
||||||
ChildPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
ChildPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
||||||
FallBackPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
FallBackPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
||||||
}
|
}
|
||||||
|
|
||||||
specialAddrForBalancerA = resolver.Address{Addr: "this.is.balancer.A"}
|
specialAddrForBalancerA = resolver.Address{Addr: "this.is.balancer.A"}
|
||||||
|
|
@ -178,8 +179,8 @@ type scStateChange struct {
|
||||||
type fakeEDSBalancer struct {
|
type fakeEDSBalancer struct {
|
||||||
cc balancer.ClientConn
|
cc balancer.ClientConn
|
||||||
edsChan chan *edspb.ClusterLoadAssignment
|
edsChan chan *edspb.ClusterLoadAssignment
|
||||||
childPolicy chan *loadBalancingConfig
|
childPolicy chan *xdsinternal.LoadBalancingConfig
|
||||||
fallbackPolicy chan *loadBalancingConfig
|
fallbackPolicy chan *xdsinternal.LoadBalancingConfig
|
||||||
subconnStateChange chan *scStateChange
|
subconnStateChange chan *scStateChange
|
||||||
loadStore lrs.Store
|
loadStore lrs.Store
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +200,7 @@ func (f *fakeEDSBalancer) HandleEDSResponse(edsResp *edspb.ClusterLoadAssignment
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeEDSBalancer) HandleChildPolicy(name string, config json.RawMessage) {
|
func (f *fakeEDSBalancer) HandleChildPolicy(name string, config json.RawMessage) {
|
||||||
f.childPolicy <- &loadBalancingConfig{
|
f.childPolicy <- &xdsinternal.LoadBalancingConfig{
|
||||||
Name: name,
|
Name: name,
|
||||||
Config: config,
|
Config: config,
|
||||||
}
|
}
|
||||||
|
|
@ -209,8 +210,8 @@ func newFakeEDSBalancer(cc balancer.ClientConn, loadStore lrs.Store) edsBalancer
|
||||||
lb := &fakeEDSBalancer{
|
lb := &fakeEDSBalancer{
|
||||||
cc: cc,
|
cc: cc,
|
||||||
edsChan: make(chan *edspb.ClusterLoadAssignment, 10),
|
edsChan: make(chan *edspb.ClusterLoadAssignment, 10),
|
||||||
childPolicy: make(chan *loadBalancingConfig, 10),
|
childPolicy: make(chan *xdsinternal.LoadBalancingConfig, 10),
|
||||||
fallbackPolicy: make(chan *loadBalancingConfig, 10),
|
fallbackPolicy: make(chan *xdsinternal.LoadBalancingConfig, 10),
|
||||||
subconnStateChange: make(chan *scStateChange, 10),
|
subconnStateChange: make(chan *scStateChange, 10),
|
||||||
loadStore: loadStore,
|
loadStore: loadStore,
|
||||||
}
|
}
|
||||||
|
|
@ -308,10 +309,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 := &xdsConfig{
|
workingLBConfig := &xdsinternal.LBConfig{
|
||||||
BalancerName: addr,
|
BalancerName: addr,
|
||||||
ChildPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
ChildPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
||||||
FallBackPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
FallBackPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
||||||
}
|
}
|
||||||
lb.UpdateClientConnState(balancer.ClientConnState{
|
lb.UpdateClientConnState(balancer.ClientConnState{
|
||||||
ResolverState: resolver.State{Addresses: addrs},
|
ResolverState: resolver.State{Addresses: addrs},
|
||||||
|
|
@ -364,39 +365,39 @@ func (s) TestXdsBalanceHandleBalancerConfigChildPolicyUpdate(t *testing.T) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
cfg *xdsConfig
|
cfg *xdsinternal.LBConfig
|
||||||
responseToSend *discoverypb.DiscoveryResponse
|
responseToSend *discoverypb.DiscoveryResponse
|
||||||
expectedChildPolicy *loadBalancingConfig
|
expectedChildPolicy *xdsinternal.LoadBalancingConfig
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
cfg: &xdsConfig{
|
cfg: &xdsinternal.LBConfig{
|
||||||
ChildPolicy: &loadBalancingConfig{
|
ChildPolicy: &xdsinternal.LoadBalancingConfig{
|
||||||
Name: fakeBalancerA,
|
Name: fakeBalancerA,
|
||||||
Config: json.RawMessage("{}"),
|
Config: json.RawMessage("{}"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
responseToSend: testEDSRespWithoutEndpoints,
|
responseToSend: testEDSRespWithoutEndpoints,
|
||||||
expectedChildPolicy: &loadBalancingConfig{
|
expectedChildPolicy: &xdsinternal.LoadBalancingConfig{
|
||||||
Name: string(fakeBalancerA),
|
Name: string(fakeBalancerA),
|
||||||
Config: json.RawMessage(`{}`),
|
Config: json.RawMessage(`{}`),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cfg: &xdsConfig{
|
cfg: &xdsinternal.LBConfig{
|
||||||
ChildPolicy: &loadBalancingConfig{
|
ChildPolicy: &xdsinternal.LoadBalancingConfig{
|
||||||
Name: fakeBalancerB,
|
Name: fakeBalancerB,
|
||||||
Config: json.RawMessage("{}"),
|
Config: json.RawMessage("{}"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
expectedChildPolicy: &loadBalancingConfig{
|
expectedChildPolicy: &xdsinternal.LoadBalancingConfig{
|
||||||
Name: string(fakeBalancerB),
|
Name: string(fakeBalancerB),
|
||||||
Config: json.RawMessage(`{}`),
|
Config: json.RawMessage(`{}`),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
cfg: &xdsConfig{},
|
cfg: &xdsinternal.LBConfig{},
|
||||||
responseToSend: testCDSResp,
|
responseToSend: testCDSResp,
|
||||||
expectedChildPolicy: &loadBalancingConfig{
|
expectedChildPolicy: &xdsinternal.LoadBalancingConfig{
|
||||||
Name: "ROUND_ROBIN",
|
Name: "ROUND_ROBIN",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -449,16 +450,16 @@ func (s) TestXdsBalanceHandleBalancerConfigFallBackUpdate(t *testing.T) {
|
||||||
|
|
||||||
addr, td, _, cleanup := setupServer(t)
|
addr, td, _, cleanup := setupServer(t)
|
||||||
|
|
||||||
cfg := xdsConfig{
|
cfg := xdsinternal.LBConfig{
|
||||||
BalancerName: addr,
|
BalancerName: addr,
|
||||||
ChildPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
ChildPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
||||||
FallBackPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
FallBackPolicy: &xdsinternal.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 = &loadBalancingConfig{Name: fakeBalancerB}
|
cfg2.FallBackPolicy = &xdsinternal.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,
|
||||||
|
|
@ -490,7 +491,7 @@ func (s) TestXdsBalanceHandleBalancerConfigFallBackUpdate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg3 := cfg
|
cfg3 := cfg
|
||||||
cfg3.FallBackPolicy = &loadBalancingConfig{Name: fakeBalancerA}
|
cfg3.FallBackPolicy = &xdsinternal.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,
|
||||||
|
|
@ -524,10 +525,10 @@ func (s) TestXdsBalancerHandlerSubConnStateChange(t *testing.T) {
|
||||||
|
|
||||||
addr, td, _, cleanup := setupServer(t)
|
addr, td, _, cleanup := setupServer(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
cfg := &xdsConfig{
|
cfg := &xdsinternal.LBConfig{
|
||||||
BalancerName: addr,
|
BalancerName: addr,
|
||||||
ChildPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
ChildPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
||||||
FallBackPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
FallBackPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
||||||
}
|
}
|
||||||
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: cfg})
|
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: cfg})
|
||||||
|
|
||||||
|
|
@ -602,10 +603,10 @@ func (s) TestXdsBalancerFallBackSignalFromEdsBalancer(t *testing.T) {
|
||||||
|
|
||||||
addr, td, _, cleanup := setupServer(t)
|
addr, td, _, cleanup := setupServer(t)
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
cfg := &xdsConfig{
|
cfg := &xdsinternal.LBConfig{
|
||||||
BalancerName: addr,
|
BalancerName: addr,
|
||||||
ChildPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
ChildPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
||||||
FallBackPolicy: &loadBalancingConfig{Name: fakeBalancerA},
|
FallBackPolicy: &xdsinternal.LoadBalancingConfig{Name: fakeBalancerA},
|
||||||
}
|
}
|
||||||
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: cfg})
|
lb.UpdateClientConnState(balancer.ClientConnState{BalancerConfig: cfg})
|
||||||
|
|
||||||
|
|
@ -673,12 +674,12 @@ func (s) TestXdsBalancerConfigParsingSelectingLBPolicy(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unable to unmarshal balancer config into xds config: %v", err)
|
t.Fatalf("unable to unmarshal balancer config into xds config: %v", err)
|
||||||
}
|
}
|
||||||
xdsCfg := cfg.(*xdsConfig)
|
xdsCfg := cfg.(*xdsinternal.LBConfig)
|
||||||
wantChildPolicy := &loadBalancingConfig{Name: string(fakeBalancerA), Config: json.RawMessage(`{}`)}
|
wantChildPolicy := &xdsinternal.LoadBalancingConfig{Name: string(fakeBalancerA), Config: json.RawMessage(`{}`)}
|
||||||
if !reflect.DeepEqual(xdsCfg.ChildPolicy, wantChildPolicy) {
|
if !reflect.DeepEqual(xdsCfg.ChildPolicy, wantChildPolicy) {
|
||||||
t.Fatalf("got child policy %v, want %v", xdsCfg.ChildPolicy, wantChildPolicy)
|
t.Fatalf("got child policy %v, want %v", xdsCfg.ChildPolicy, wantChildPolicy)
|
||||||
}
|
}
|
||||||
wantFallbackPolicy := &loadBalancingConfig{Name: string(fakeBalancerB), Config: json.RawMessage(`{}`)}
|
wantFallbackPolicy := &xdsinternal.LoadBalancingConfig{Name: string(fakeBalancerB), Config: json.RawMessage(`{}`)}
|
||||||
if !reflect.DeepEqual(xdsCfg.FallBackPolicy, wantFallbackPolicy) {
|
if !reflect.DeepEqual(xdsCfg.FallBackPolicy, wantFallbackPolicy) {
|
||||||
t.Fatalf("got fallback policy %v, want %v", xdsCfg.FallBackPolicy, wantFallbackPolicy)
|
t.Fatalf("got fallback policy %v, want %v", xdsCfg.FallBackPolicy, wantFallbackPolicy)
|
||||||
}
|
}
|
||||||
|
|
@ -688,18 +689,18 @@ func (s) TestXdsLoadbalancingConfigParsing(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
s string
|
s string
|
||||||
want *xdsConfig
|
want *xdsinternal.LBConfig
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "empty",
|
name: "empty",
|
||||||
s: "{}",
|
s: "{}",
|
||||||
want: &xdsConfig{},
|
want: &xdsinternal.LBConfig{},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "success1",
|
name: "success1",
|
||||||
s: `{"childPolicy":[{"pick_first":{}}]}`,
|
s: `{"childPolicy":[{"pick_first":{}}]}`,
|
||||||
want: &xdsConfig{
|
want: &xdsinternal.LBConfig{
|
||||||
ChildPolicy: &loadBalancingConfig{
|
ChildPolicy: &xdsinternal.LoadBalancingConfig{
|
||||||
Name: "pick_first",
|
Name: "pick_first",
|
||||||
Config: json.RawMessage(`{}`),
|
Config: json.RawMessage(`{}`),
|
||||||
},
|
},
|
||||||
|
|
@ -708,8 +709,8 @@ func (s) TestXdsLoadbalancingConfigParsing(t *testing.T) {
|
||||||
{
|
{
|
||||||
name: "success2",
|
name: "success2",
|
||||||
s: `{"childPolicy":[{"round_robin":{}},{"pick_first":{}}]}`,
|
s: `{"childPolicy":[{"round_robin":{}},{"pick_first":{}}]}`,
|
||||||
want: &xdsConfig{
|
want: &xdsinternal.LBConfig{
|
||||||
ChildPolicy: &loadBalancingConfig{
|
ChildPolicy: &xdsinternal.LoadBalancingConfig{
|
||||||
Name: "round_robin",
|
Name: "round_robin",
|
||||||
Config: json.RawMessage(`{}`),
|
Config: json.RawMessage(`{}`),
|
||||||
},
|
},
|
||||||
|
|
@ -718,7 +719,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 xdsConfig
|
var cfg xdsinternal.LBConfig
|
||||||
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,8 +18,11 @@
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/balancer"
|
||||||
|
"google.golang.org/grpc/serviceconfig"
|
||||||
basepb "google.golang.org/grpc/xds/internal/proto/envoy/api/v2/core/base"
|
basepb "google.golang.org/grpc/xds/internal/proto/envoy/api/v2/core/base"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -48,3 +51,88 @@ func (lamk Locality) ToProto() *basepb.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 enconding 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 enconding 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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 resolver implements the xds resolver.
|
||||||
|
//
|
||||||
|
// At this point, the resolver is named xds-experimental, and doesn't do very
|
||||||
|
// much at all, except for returning a hard-coded service config which selects
|
||||||
|
// the xds_experimental balancer.
|
||||||
|
package resolver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/internal"
|
||||||
|
"google.golang.org/grpc/resolver"
|
||||||
|
"google.golang.org/grpc/serviceconfig"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// The JSON form of the hard-coded service config which picks the
|
||||||
|
// xds_experimental balancer with round_robin as the child policy.
|
||||||
|
jsonSC = `{
|
||||||
|
"loadBalancingConfig":[
|
||||||
|
{
|
||||||
|
"xds_experimental":{
|
||||||
|
"childPolicy":[
|
||||||
|
{
|
||||||
|
"round_robin": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`
|
||||||
|
// xDS balancer name is xds_experimental while resolver scheme is
|
||||||
|
// xds-experimental since "_" is not a valid character in the URL.
|
||||||
|
xdsScheme = "xds-experimental"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
parseOnce sync.Once
|
||||||
|
parsedSC serviceconfig.Config
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewBuilder creates a new implementation of the resolver.Builder interface
|
||||||
|
// for the xDS resolver.
|
||||||
|
func NewBuilder() resolver.Builder {
|
||||||
|
return &xdsBuilder{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type xdsBuilder struct{}
|
||||||
|
|
||||||
|
// Build helps implement the resolver.Builder interface.
|
||||||
|
func (b *xdsBuilder) Build(t resolver.Target, cc resolver.ClientConn, o resolver.BuildOption) (resolver.Resolver, error) {
|
||||||
|
parseOnce.Do(func() {
|
||||||
|
// The xds balancer must have been registered at this point for the service
|
||||||
|
// config to be parsed properly.
|
||||||
|
psc, err := internal.ParseServiceConfig(jsonSC)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("service config %s parsing failed: %v", jsonSC, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
var ok bool
|
||||||
|
if parsedSC, ok = psc.(*grpc.ServiceConfig); !ok {
|
||||||
|
panic(fmt.Sprintf("service config type is [%T], want [grpc.ServiceConfig]", psc))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// We return a resolver which bacically does nothing. The hard-coded service
|
||||||
|
// config returned here picks the xds balancer.
|
||||||
|
cc.UpdateState(resolver.State{ServiceConfig: parsedSC})
|
||||||
|
return &xdsResolver{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name helps implement the resolver.Builder interface.
|
||||||
|
func (*xdsBuilder) Scheme() string {
|
||||||
|
return xdsScheme
|
||||||
|
}
|
||||||
|
|
||||||
|
type xdsResolver struct{}
|
||||||
|
|
||||||
|
// ResolveNow is a no-op at this point.
|
||||||
|
func (*xdsResolver) ResolveNow(o resolver.ResolveNowOption) {}
|
||||||
|
|
||||||
|
// Close is a no-op at this point.
|
||||||
|
func (*xdsResolver) Close() {}
|
||||||
|
|
@ -0,0 +1,196 @@
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* 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 resolver
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/balancer"
|
||||||
|
"google.golang.org/grpc/connectivity"
|
||||||
|
"google.golang.org/grpc/resolver"
|
||||||
|
"google.golang.org/grpc/serviceconfig"
|
||||||
|
xdsinternal "google.golang.org/grpc/xds/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is initialized at init time.
|
||||||
|
var fbb *fakeBalancerBuilder
|
||||||
|
|
||||||
|
// We register a fake balancer builder and the actual xds_resolver here. We use
|
||||||
|
// the fake balancer builder to verify the service config pushed by the
|
||||||
|
// resolver.
|
||||||
|
func init() {
|
||||||
|
resolver.Register(NewBuilder())
|
||||||
|
fbb = &fakeBalancerBuilder{
|
||||||
|
wantLBConfig: &wrappedLBConfig{lbCfg: json.RawMessage(`{
|
||||||
|
"childPolicy":[
|
||||||
|
{
|
||||||
|
"round_robin": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}`)},
|
||||||
|
errCh: make(chan error),
|
||||||
|
}
|
||||||
|
balancer.Register(fbb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// testClientConn is a fake implemetation of resolver.ClientConn. All is does
|
||||||
|
// is to store the state received from the resolver locally and close the
|
||||||
|
// provided done channel.
|
||||||
|
type testClientConn struct {
|
||||||
|
done chan struct{}
|
||||||
|
gotState resolver.State
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *testClientConn) UpdateState(s resolver.State) {
|
||||||
|
t.gotState = s
|
||||||
|
close(t.done)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*testClientConn) NewAddress(addresses []resolver.Address) { panic("unimplemented") }
|
||||||
|
func (*testClientConn) NewServiceConfig(serviceConfig string) { panic("unimplemented") }
|
||||||
|
|
||||||
|
// TestXDSRsolverSchemeAndAddresses creates a new xds resolver, verifies that
|
||||||
|
// it returns an empty address list and the appropriate xds-experimental
|
||||||
|
// scheme.
|
||||||
|
func TestXDSRsolverSchemeAndAddresses(t *testing.T) {
|
||||||
|
b := NewBuilder()
|
||||||
|
wantScheme := "xds-experimental"
|
||||||
|
if b.Scheme() != wantScheme {
|
||||||
|
t.Fatalf("got scheme %s, want %s", b.Scheme(), wantScheme)
|
||||||
|
}
|
||||||
|
|
||||||
|
tcc := &testClientConn{done: make(chan struct{})}
|
||||||
|
r, err := b.Build(resolver.Target{}, tcc, resolver.BuildOption{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("xdsBuilder.Build() failed with error: %v", err)
|
||||||
|
}
|
||||||
|
defer r.Close()
|
||||||
|
|
||||||
|
<-tcc.done
|
||||||
|
if len(tcc.gotState.Addresses) != 0 {
|
||||||
|
t.Fatalf("got address list from resolver %v, want empty list", tcc.gotState.Addresses)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fakeBalancer is used to verify that the xds_resolver returns the expected
|
||||||
|
// serice config.
|
||||||
|
type fakeBalancer struct {
|
||||||
|
wantLBConfig *wrappedLBConfig
|
||||||
|
errCh chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeBalancer) HandleSubConnStateChange(_ balancer.SubConn, _ connectivity.State) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
func (*fakeBalancer) HandleResolvedAddrs(_ []resolver.Address, _ error) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// UpdateClientConnState verifies that the received LBConfig matches the
|
||||||
|
// provided one, and if not, sends an error on the provided channel.
|
||||||
|
func (f *fakeBalancer) UpdateClientConnState(ccs balancer.ClientConnState) {
|
||||||
|
gotLBConfig, ok := ccs.BalancerConfig.(*wrappedLBConfig)
|
||||||
|
if !ok {
|
||||||
|
f.errCh <- fmt.Errorf("in fakeBalancer got lbConfig of type %T, want %T", ccs.BalancerConfig, &wrappedLBConfig{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var gotCfg, wantCfg xdsinternal.LBConfig
|
||||||
|
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))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := gotCfg.UnmarshalJSON(gotLBConfig.lbCfg); err != nil {
|
||||||
|
f.errCh <- fmt.Errorf("unable to unmarshal balancer config %s into xds config", string(gotLBConfig.lbCfg))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(gotCfg, wantCfg) {
|
||||||
|
f.errCh <- fmt.Errorf("in fakeBalancer got lbConfig %v, want %v", gotCfg, wantCfg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.errCh <- nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeBalancer) UpdateSubConnState(_ balancer.SubConn, _ balancer.SubConnState) {
|
||||||
|
panic("unimplemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*fakeBalancer) Close() {}
|
||||||
|
|
||||||
|
// fakeBalancerBuilder builds a fake balancer and also provides a ParseConfig
|
||||||
|
// method (which doesn't really the parse config, but just stores it as is).
|
||||||
|
type fakeBalancerBuilder struct {
|
||||||
|
wantLBConfig *wrappedLBConfig
|
||||||
|
errCh chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeBalancerBuilder) Build(cc balancer.ClientConn, opts balancer.BuildOptions) balancer.Balancer {
|
||||||
|
return &fakeBalancer{f.wantLBConfig, f.errCh}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeBalancerBuilder) Name() string {
|
||||||
|
return "xds_experimental"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *fakeBalancerBuilder) ParseConfig(c json.RawMessage) (serviceconfig.LoadBalancingConfig, error) {
|
||||||
|
return &wrappedLBConfig{lbCfg: c}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrappedLBConfig simply wraps the provided LB config with a
|
||||||
|
// serviceconfig.LoadBalancingConfig interface.
|
||||||
|
type wrappedLBConfig struct {
|
||||||
|
serviceconfig.LoadBalancingConfig
|
||||||
|
lbCfg json.RawMessage
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestXDSRsolverServiceConfig verifies that the xds_resolver returns the
|
||||||
|
// expected service config.
|
||||||
|
//
|
||||||
|
// The following sequence of events happen in this test:
|
||||||
|
// * The xds_experimental balancer (fake) and resolver builders are initialized
|
||||||
|
// at init time.
|
||||||
|
// * We dial a dummy address here with the xds-experimental scheme. This should
|
||||||
|
// pick the xds_resolver, which should return the hard-coded service config,
|
||||||
|
// which should reach the fake balancer that we registered (because the
|
||||||
|
// service config asks for the xds balancer).
|
||||||
|
// * In the fake balancer, we verify that we receive the expected LB config.
|
||||||
|
func TestXDSRsolverServiceConfig(t *testing.T) {
|
||||||
|
xdsAddr := fmt.Sprintf("%s:///dummy", xdsScheme)
|
||||||
|
cc, err := grpc.Dial(xdsAddr, grpc.WithInsecure())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("grpc.Dial(%s) failed with error: %v", xdsAddr, err)
|
||||||
|
}
|
||||||
|
defer cc.Close()
|
||||||
|
|
||||||
|
timer := time.NewTimer(5 * time.Second)
|
||||||
|
select {
|
||||||
|
case <-timer.C:
|
||||||
|
t.Fatal("timed out waiting for service config to reach balancer")
|
||||||
|
case err := <-fbb.errCh:
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue