Skip to content

Commit 1137102

Browse files
authored
Merge pull request #2540 from murgatroid99/grpc-js-xds_lrs_config_handling_fix
grpc-js-xds: Fix handling of LRS server configs
2 parents 4d288de + 7ae331b commit 1137102

File tree

6 files changed

+61
-25
lines changed

6 files changed

+61
-25
lines changed

packages/grpc-js-xds/src/load-balancer-lrs.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class LrsLoadBalancingConfig implements TypedLoadBalancingConfig {
9797
if (!('child_policy' in obj && Array.isArray(obj.child_policy))) {
9898
throw new Error('lrs config must have a child_policy array');
9999
}
100-
const childConfig = selectLbConfigFromList(obj.config);
100+
const childConfig = selectLbConfigFromList(obj.child_policy);
101101
if (!childConfig) {
102102
throw new Error('lrs config child_policy parsing failed');
103103
}

packages/grpc-js-xds/src/load-balancer-xds-cluster-resolver.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,8 @@ export class XdsClusterResolver implements LoadBalancer {
310310
cluster_name: entry.discoveryMechanism.cluster,
311311
eds_service_name: entry.discoveryMechanism.eds_service_name ?? '',
312312
locality: {...localityObj.locality},
313-
lrs_load_reporting_server: {...entry.discoveryMechanism.lrs_load_reporting_server}
313+
lrs_load_reporting_server: {...entry.discoveryMechanism.lrs_load_reporting_server},
314+
child_policy: endpointPickingPolicy
314315
}
315316
}];
316317
} else {

packages/grpc-js-xds/src/xds-bootstrap.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,9 @@ export interface ChannelCredsConfig {
4141
}
4242

4343
export interface XdsServerConfig {
44-
serverUri: string;
45-
channelCreds: ChannelCredsConfig[];
46-
serverFeatures: string[];
44+
server_uri: string;
45+
channel_creds: ChannelCredsConfig[];
46+
server_features: string[];
4747
}
4848

4949
export interface Authority {
@@ -61,19 +61,19 @@ export interface BootstrapInfo {
6161
const KNOWN_SERVER_FEATURES = ['ignore_resource_deletion'];
6262

6363
export function serverConfigEqual(config1: XdsServerConfig, config2: XdsServerConfig): boolean {
64-
if (config1.serverUri !== config2.serverUri) {
64+
if (config1.server_uri !== config2.server_uri) {
6565
return false;
6666
}
6767
for (const feature of KNOWN_SERVER_FEATURES) {
68-
if ((feature in config1.serverFeatures) !== (feature in config2.serverFeatures)) {
68+
if ((feature in config1.server_features) !== (feature in config2.server_features)) {
6969
return false;
7070
}
7171
}
72-
if (config1.channelCreds.length !== config2.channelCreds.length) {
72+
if (config1.channel_creds.length !== config2.channel_creds.length) {
7373
return false;
7474
}
75-
for (const [index, creds1] of config1.channelCreds.entries()) {
76-
const creds2 = config2.channelCreds[index];
75+
for (const [index, creds1] of config1.channel_creds.entries()) {
76+
const creds2 = config2.channel_creds[index];
7777
if (creds1.type !== creds2.type) {
7878
return false;
7979
}
@@ -93,7 +93,7 @@ function validateChannelCredsConfig(obj: any): ChannelCredsConfig {
9393
`xds_servers.channel_creds.type field: expected string, got ${typeof obj.type}`
9494
);
9595
}
96-
if ('config' in obj) {
96+
if ('config' in obj && obj.config !== undefined) {
9797
if (typeof obj.config !== 'object' || obj.config === null) {
9898
throw new Error(
9999
'xds_servers.channel_creds config field must be an object if provided'
@@ -152,9 +152,9 @@ export function validateXdsServerConfig(obj: any): XdsServerConfig {
152152
}
153153
}
154154
return {
155-
serverUri: obj.server_uri,
156-
channelCreds: obj.channel_creds.map(validateChannelCredsConfig),
157-
serverFeatures: obj.server_features ?? []
155+
server_uri: obj.server_uri,
156+
channel_creds: obj.channel_creds.map(validateChannelCredsConfig),
157+
server_features: obj.server_features ?? []
158158
};
159159
}
160160

@@ -387,7 +387,7 @@ export function loadBootstrapInfo(): BootstrapInfo {
387387
return loadedBootstrapInfo;
388388
}
389389

390-
390+
391391
throw new Error(
392392
'The GRPC_XDS_BOOTSTRAP or GRPC_XDS_BOOTSTRAP_CONFIG environment variables need to be set to the path to the bootstrap file to use xDS'
393393
);

packages/grpc-js-xds/src/xds-client.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -602,9 +602,9 @@ class ClusterLoadReportMap {
602602
* Get the indicated map entry if it exists, or create a new one if it does
603603
* not. Increments the refcount of that entry, so a call to this method
604604
* should correspond to a later call to unref
605-
* @param clusterName
606-
* @param edsServiceName
607-
* @returns
605+
* @param clusterName
606+
* @param edsServiceName
607+
* @returns
608608
*/
609609
getOrCreate(clusterName: string, edsServiceName: string): ClusterLoadReport {
610610
for (const statsObj of this.statsMap) {
@@ -833,12 +833,12 @@ class XdsSingleServerClient {
833833
this.maybeStartLrsStream();
834834
});
835835
this.lrsBackoff.unref();
836-
this.ignoreResourceDeletion = xdsServerConfig.serverFeatures.includes('ignore_resource_deletion');
836+
this.ignoreResourceDeletion = xdsServerConfig.server_features.includes('ignore_resource_deletion');
837837
const channelArgs = {
838838
// 5 minutes
839839
'grpc.keepalive_time_ms': 5 * 60 * 1000
840840
}
841-
const credentialsConfigs = xdsServerConfig.channelCreds;
841+
const credentialsConfigs = xdsServerConfig.channel_creds;
842842
let channelCreds: ChannelCredentials | null = null;
843843
for (const config of credentialsConfigs) {
844844
if (config.type === 'google_default') {
@@ -849,8 +849,8 @@ class XdsSingleServerClient {
849849
break;
850850
}
851851
}
852-
const serverUri = this.xdsServerConfig.serverUri
853-
this.trace('Starting xDS client connected to server URI ' + this.xdsServerConfig.serverUri);
852+
const serverUri = this.xdsServerConfig.server_uri
853+
this.trace('Starting xDS client connected to server URI ' + this.xdsServerConfig.server_uri);
854854
/* Bootstrap validation rules guarantee that a matching channel credentials
855855
* config exists in the list. */
856856
const channel = new Channel(serverUri, channelCreds!, channelArgs);
@@ -949,7 +949,7 @@ class XdsSingleServerClient {
949949
}
950950

951951
trace(text: string) {
952-
trace(this.xdsServerConfig.serverUri + ' ' + text);
952+
trace(this.xdsServerConfig.server_uri + ' ' + text);
953953
}
954954

955955
subscribe(type: XdsResourceType, name: XdsResourceName) {

packages/grpc-js-xds/test/framework.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@ export class FakeEdsCluster implements FakeCluster {
8383
name: this.clusterName,
8484
type: 'EDS',
8585
eds_cluster_config: {eds_config: {ads: {}}, service_name: this.endpointName},
86-
lb_policy: 'ROUND_ROBIN'
86+
lb_policy: 'ROUND_ROBIN',
87+
lrs_server: {self: {}}
8788
}
8889
}
8990

@@ -156,7 +157,8 @@ export class FakeDnsCluster implements FakeCluster {
156157
}
157158
}]
158159
}]
159-
}
160+
},
161+
lrs_server: {self: {}}
160162
};
161163
}
162164
getAllClusterConfigs(): Cluster[] {
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2023 gRPC authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
*/
17+
18+
import * as assert from 'assert';
19+
import { validateXdsServerConfig } from "../src/xds-bootstrap";
20+
21+
describe('bootstrap', () => {
22+
/* validateXdsServerConfig is used when creating the cds config, and then
23+
* the resulting value is validated again when creating the
24+
* xds_cluster_resolver config. */
25+
it('validateXdsServerConfig should be idempotent', () => {
26+
const config = {
27+
server_uri: 'localhost',
28+
channel_creds: [{type: 'google_default'}],
29+
server_features: ['test_feature']
30+
};
31+
assert.deepStrictEqual(validateXdsServerConfig(validateXdsServerConfig(config)), validateXdsServerConfig(config));
32+
});
33+
});

0 commit comments

Comments
 (0)