Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 25 additions & 63 deletions internal/xds/balancer/cdsbalancer/aggregate_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ func verifyDNSResolution(ctx context.Context, t *testing.T, dnsTargetCh chan res

// Tests the case where the cluster resource requested is a leaf cluster. The
// management server sends two updates for the same leaf cluster resource. The
// test verifies that the load balancing configuration pushed to the priority LB
// policy contains the expected discovery mechanism corresponding to the leaf
// test verifies that the load balancing configuration pushed to the top-level LB

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrap the comment in 80 column.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

// policy contains the expected configuration corresponding to the leaf
// cluster, on both occasions.
func (s) TestAggregateClusterSuccess_LeafNode(t *testing.T) {
tests := []struct {
Expand All @@ -105,43 +105,21 @@ func (s) TestAggregateClusterSuccess_LeafNode(t *testing.T) {
name: "eds",
firstClusterResource: e2e.DefaultCluster(clusterName, serviceName, e2e.SecurityLevelNone),
secondClusterResource: e2e.DefaultCluster(clusterName, serviceName+"-new", e2e.SecurityLevelNone),
wantFirstChildCfg: &priority.LBConfig{
Children: map[string]*priority.Child{
"priority-0-0": {
Config: createPriorityConfig(clusterName),
IgnoreReresolutionRequests: true,
},
},
Priorities: []string{"priority-0-0"},
},
wantSecondChildCfg: &priority.LBConfig{
Children: map[string]*priority.Child{
"priority-1-0": {
Config: createPriorityConfig(clusterName),
IgnoreReresolutionRequests: true,
},
},
Priorities: []string{"priority-1-0"},
},
wantFirstChildCfg: createSingleClusterConfig(clusterName, "priority-0-0", true),
wantSecondChildCfg: createSingleClusterConfig(clusterName, "priority-1-0", true),
},
{
name: "dns",
firstClusterResource: makeLogicalDNSClusterResource(clusterName, "dns_host", uint32(port)),
secondClusterResource: makeLogicalDNSClusterResource(clusterName, "dns_host_new", uint32(port)),
wantFirstChildCfg: &priority.LBConfig{
Children: map[string]*priority.Child{"priority-0": {Config: createPriorityConfig(clusterName)}},
Priorities: []string{"priority-0"},
},
wantSecondChildCfg: &priority.LBConfig{
Children: map[string]*priority.Child{"priority-1": {Config: createPriorityConfig(clusterName)}},
Priorities: []string{"priority-1"},
},
wantFirstChildCfg: createSingleClusterConfig(clusterName, "priority-0", false),
wantSecondChildCfg: createSingleClusterConfig(clusterName, "priority-1", false),
},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
lbCfgCh, _, _, _ := registerWrappedPriorityPolicy(t)
lbCfgCh := registerWrappedOutlierDetectionPolicy(t)
mgmtServer, nodeID, _ := setupWithManagementServer(t, nil, nil)

// Push the first cluster resource through the management server and
Expand Down Expand Up @@ -281,11 +259,11 @@ func (s) TestAggregateClusterSuccess_ThenUpdateChildClusters(t *testing.T) {
// the priority LB policy contains the discovery mechanisms for both child
// clusters. The test then updates the root cluster resource requested by the
// cds LB policy to a leaf cluster of type EDS and verifies the load balancing
// configuration pushed to the priority LB policy contains a single discovery
// mechanism.
// configuration pushed to the outlier detection LB policy contains the leaf cluster config.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, please wrap the comment in 80 column. Here and elsewhere.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

func (s) TestAggregateClusterSuccess_ThenChangeRootToEDS(t *testing.T) {
dnsTargetCh, dnsR := setupDNS(t)
lbCfgCh, _, _, _ := registerWrappedPriorityPolicy(t)
odCfgCh := registerWrappedOutlierDetectionPolicy(t)
mgmtServer, nodeID, _ := setupWithManagementServer(t, nil, nil)

// Configure the management server with the aggregate cluster resource
Expand Down Expand Up @@ -332,32 +310,29 @@ func (s) TestAggregateClusterSuccess_ThenChangeRootToEDS(t *testing.T) {
},
Endpoints: []*v3endpointpb.ClusterLoadAssignment{e2e.DefaultEndpoint(serviceName, host, []uint32{port})},
}
// Drain odCfgCh before sending non-aggregate update, as aggregate children pushed outlier configs into odCfgCh.
for len(odCfgCh) > 0 {
<-odCfgCh
}
if err := mgmtServer.Update(ctx, resources); err != nil {
t.Fatal(err)
}
// Since the service name of the EDS cluster remains same, same priority name
// is used.
wantChildCfg = &priority.LBConfig{
Children: map[string]*priority.Child{
"priority-0-0": {
Config: createPriorityConfig(clusterName),
IgnoreReresolutionRequests: true,
},
},
Priorities: []string{"priority-0-0"},
}
if err := compareLoadBalancingConfig(ctx, lbCfgCh, wantChildCfg); err != nil {
wantSingleChildCfg := createSingleClusterConfig(clusterName, "priority-0-0", true)
if err := compareLoadBalancingConfig(ctx, odCfgCh, wantSingleChildCfg); err != nil {
t.Fatal(err)
}
}

// Tests the case where a requested cluster resource switches between being a
// leaf and an aggregate cluster pointing to an EDS and LogicalDNS child
// cluster. In each of these cases, the test verifies that the load balancing
// configuration pushed to the priority LB policy contains the expected config.
// configuration pushed to the top-level child policy contains the expected config.
func (s) TestAggregatedClusterSuccess_SwitchBetweenLeafAndAggregate(t *testing.T) {
dnsTargetCh, dnsR := setupDNS(t)
lbCfgCh, _, _, _ := registerWrappedPriorityPolicy(t)
odCfgCh := registerWrappedOutlierDetectionPolicy(t)
mgmtServer, nodeID, _ := setupWithManagementServer(t, nil, nil)

// Start off with the requested cluster being a leaf EDS cluster.
Expand All @@ -373,16 +348,8 @@ func (s) TestAggregatedClusterSuccess_SwitchBetweenLeafAndAggregate(t *testing.T
if err := mgmtServer.Update(ctx, resources); err != nil {
t.Fatal(err)
}
wantChildCfg := &priority.LBConfig{
Children: map[string]*priority.Child{
"priority-0-0": {
Config: createPriorityConfig(clusterName),
IgnoreReresolutionRequests: true,
},
},
Priorities: []string{"priority-0-0"},
}
if err := compareLoadBalancingConfig(ctx, lbCfgCh, wantChildCfg); err != nil {
wantSingleChildCfg := createSingleClusterConfig(clusterName, "priority-0-0", true)
if err := compareLoadBalancingConfig(ctx, odCfgCh, wantSingleChildCfg); err != nil {
t.Fatal(err)
}

Expand All @@ -404,7 +371,7 @@ func (s) TestAggregatedClusterSuccess_SwitchBetweenLeafAndAggregate(t *testing.T
}
verifyDNSResolution(ctx, t, dnsTargetCh, dnsR, dnsHostName, dnsPort)

wantChildCfg = &priority.LBConfig{
wantChildCfg := &priority.LBConfig{
Children: map[string]*priority.Child{
"priority-0-0": {
Config: createPriorityConfig(edsClusterName),
Expand All @@ -426,19 +393,14 @@ func (s) TestAggregatedClusterSuccess_SwitchBetweenLeafAndAggregate(t *testing.T
Clusters: []*v3clusterpb.Cluster{e2e.DefaultCluster(clusterName, serviceName, e2e.SecurityLevelNone)},
Endpoints: []*v3endpointpb.ClusterLoadAssignment{e2e.DefaultEndpoint(serviceName, host, []uint32{port})},
}
// Drain odCfgCh before sending non-aggregate update, as aggregate children pushed outlier configs into odCfgCh.
for len(odCfgCh) > 0 {
<-odCfgCh
}
if err := mgmtServer.Update(ctx, resources); err != nil {
t.Fatal(err)
}
wantChildCfg = &priority.LBConfig{
Children: map[string]*priority.Child{
"priority-0-0": {
Config: createPriorityConfig(clusterName),
IgnoreReresolutionRequests: true,
},
},
Priorities: []string{"priority-0-0"},
}
if err := compareLoadBalancingConfig(ctx, lbCfgCh, wantChildCfg); err != nil {
if err := compareLoadBalancingConfig(ctx, odCfgCh, wantSingleChildCfg); err != nil {
t.Fatal(err)
}
}
Expand Down
52 changes: 42 additions & 10 deletions internal/xds/balancer/cdsbalancer/cdsbalancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,20 @@ import (
const cdsName = "cds_experimental"

var (
// newChildBalancer is a helper function to build a new priority balancer
// and will be overridden in unittests.
newChildBalancer = func(cc balancer.ClientConn, opts balancer.BuildOptions) (balancer.Balancer, error) {
builder := balancer.Get(priority.Name)
// newChildBalancer is a helper function to build a new child balancer and its
// config parser, and will be overridden in unittests.
Comment thread
Pranjali-2501 marked this conversation as resolved.
Outdated
newChildBalancer = func(name string, cc balancer.ClientConn, opts balancer.BuildOptions) (balancer.Balancer, balancer.ConfigParser, error) {
builder := balancer.Get(name)
Comment on lines +45 to +46

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use gracefulswitch.Balancer here and make cdsBalancer.childLB of type *gracefulswitch.Balancer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

newChildBalancer function and its output have been removed as gracefulswitch.Balancer and gracefulswitch.ParseConfig implementation already covers the same functionality

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to start a discussion on this before making any change and want to hear your thoughts on this.

Now based on my offline discussions with @easwars, We don't need to use gracefulSwitch here because it is very rare that the type of cluster get changed.

Could you please revert back the changes you made to use gracefulSwitch.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, I have reverted it

if builder == nil {
return nil, fmt.Errorf("xds: no balancer builder with name %v", priority.Name)
return nil, nil, fmt.Errorf("xds: no balancer builder with name %v", name)
}
// We directly pass the parent clientConn to the underlying priority
parser, ok := builder.(balancer.ConfigParser)
if !ok {
return nil, nil, fmt.Errorf("xds: balancer builder for %v does not implement ConfigParser", name)
}
Comment on lines +50 to +53

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you have added the logic to retrieve the childConfigParser here, we can remove it from `Build()``.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this has been removed as a result of using gracefulswitch.Balancer

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setting childConfigParser in Build has been removed

// We directly pass the parent clientConn to the underlying child
// balancer because the cdsBalancer does not deal with subConns.
return builder.Build(cc, opts), nil
return builder.Build(cc, opts), parser, nil
}
)

Expand Down Expand Up @@ -134,6 +138,7 @@ type cdsBalancer struct {
// protect access to these fields.
xdsClient xdsclient.XDSClient
childLB balancer.Balancer // Child policy, built upon resolution of the cluster graph.
childLBName string // Name of the child policy.
clusterConfigs map[string]*xdsresource.ClusterResult // Cluster name to the last received result for that cluster.
priorityConfigs map[string]*priorityConfig // Hostname to priority config for that leaf cluster.
lbCfg *lbConfig // Current load balancing configuration.
Expand Down Expand Up @@ -267,18 +272,45 @@ func (b *cdsBalancer) handleClusterUpdate() error {
// A child policy is created if one doesn't already exist. The newly built
// configuration is then pushed to the child policy.
func (b *cdsBalancer) updateChildConfig() error {
clusterName := b.lbCfg.ClusterName
clusterConfig := b.clusterConfigs[clusterName].Config
isAggregate := clusterConfig.Cluster.ClusterType == xdsresource.ClusterTypeAggregate
Comment thread
mswierq marked this conversation as resolved.

var topLBName string
if isAggregate {
topLBName = priority.Name
} else {
topLBName = outlierdetection.Name
}

if b.childLB != nil && b.childLBName != topLBName {
b.childLB.Close()
b.childLB = nil
}

if b.childLB == nil {
childLB, err := newChildBalancer(b.cc, b.bOpts)
childLB, parser, err := newChildBalancer(topLBName, b.cc, b.bOpts)
if err != nil {
return fmt.Errorf("failed to create child policy of type %s: %v", priority.Name, err)
return fmt.Errorf("failed to create child policy of type %s: %v", topLBName, err)
}
b.childLB = childLB
b.childLBName = topLBName
b.childConfigParser = parser
}

childCfgBytes, endpoints, err := buildPriorityConfigJSON(b.priorities, &b.xdsLBPolicy)
var childCfgBytes []byte
var endpoints []resolver.Endpoint
var err error

if isAggregate {
childCfgBytes, endpoints, err = buildAggregateClusterPriorityConfigJSON(b.priorities, &b.xdsLBPolicy)
} else {
childCfgBytes, endpoints, err = buildSingleClusterConfigJSON(b.priorities[0], &b.xdsLBPolicy)
}
Comment thread
mswierq marked this conversation as resolved.
Comment on lines +289 to +293

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the variable topLBName can be set here only instead of setting it in another if-else block.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after reverting gracefulswitch this actually has to stay that way, because we need to check first if the top policy type has changed due to update (e.g. update from non-aggregate to aggregate cluster)

if err != nil {
return fmt.Errorf("failed to build child policy config: %v", err)
}

childCfg, err := b.childConfigParser.ParseConfig(childCfgBytes)
if err != nil {
return fmt.Errorf("failed to parse child policy config. This should never happen because the config was generated: %v", err)
Expand Down
Loading
Loading