Skip to content

Commit 9ca8302

Browse files
committed
Add tests and fix bugs
1 parent 7326035 commit 9ca8302

File tree

12 files changed

+239
-23
lines changed

12 files changed

+239
-23
lines changed

packages/grpc-js-xds/gulpfile.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ const compile = checkTask(() => execNpmCommand('compile'));
6262

6363
const runTests = checkTask(() => {
6464
process.env.GRPC_EXPERIMENTAL_XDS_FEDERATION = 'true';
65+
process.env.GRPC_EXPERIMENTAL_XDS_CUSTOM_LB_CONFIG = 'true';
6566
return gulp.src(`${outDir}/test/**/*.js`)
6667
.pipe(mocha({reporter: 'mocha-jenkins-reporter',
6768
require: ['ts-node/register']}));

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import parseLoadBalancingConfig = grpc.experimental.parseLoadBalancingConfig;
4444

4545
grpc_xds.register();
4646

47-
const LB_POLICY_NAME = 'RpcBehaviorLoadBalancer';
47+
const LB_POLICY_NAME = 'test.RpcBehaviorLoadBalancer';
4848

4949
class RpcBehaviorLoadBalancingConfig implements TypedLoadBalancingConfig {
5050
constructor(private rpcBehavior: string) {}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import * as xds_wrr_locality from './load-balancer-xds-wrr-locality';
2626
import * as router_filter from './http-filter/router-filter';
2727
import * as fault_injection_filter from './http-filter/fault-injection-filter';
2828
import * as csds from './csds';
29+
import * as round_robin_lb from './lb-policy-registry/round-robin';
30+
import * as typed_struct_lb from './lb-policy-registry/typed-struct';
2931

3032
/**
3133
* Register the "xds:" name scheme with the @grpc/grpc-js library.
@@ -42,4 +44,6 @@ export function register() {
4244
router_filter.setup();
4345
fault_injection_filter.setup();
4446
csds.setup();
47+
round_robin_lb.setup();
48+
typed_struct_lb.setup();
4549
}

packages/grpc-js-xds/src/lb-policy-registry.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@ function trace(text: string) {
2626

2727
const MAX_RECURSION_DEPTH = 16;
2828

29+
/**
30+
* Parse a protoPolicy to a LoadBalancingConfig. A null return value indicates
31+
* that parsing failed, but that it should not be treated as an error, and
32+
* instead the next policy should be used.
33+
*/
2934
interface ProtoLbPolicyConverter {
30-
(protoPolicy: TypedExtensionConfig__Output, selectChildPolicy: (childPolicy: LoadBalancingPolicy__Output) => LoadBalancingConfig): LoadBalancingConfig
35+
(protoPolicy: TypedExtensionConfig__Output, selectChildPolicy: (childPolicy: LoadBalancingPolicy__Output) => LoadBalancingConfig): LoadBalancingConfig | null;
3136
}
3237

3338
interface RegisteredLbPolicy {
@@ -41,20 +46,29 @@ export function registerLbPolicy(typeUrl: string, converter: ProtoLbPolicyConver
4146
}
4247

4348
export function convertToLoadBalancingConfig(protoPolicy: LoadBalancingPolicy__Output, recursionDepth = 0): LoadBalancingConfig {
49+
trace('Registry entries: [' + Object.keys(registry) + ']');
4450
if (recursionDepth > MAX_RECURSION_DEPTH) {
4551
throw new Error(`convertToLoadBalancingConfig: Max recursion depth ${MAX_RECURSION_DEPTH} reached`);
4652
}
4753
for (const policyCandidate of protoPolicy.policies) {
54+
trace('Attempting to parse config ' + JSON.stringify(policyCandidate));
4855
const extensionConfig = policyCandidate.typed_extension_config;
4956
if (!extensionConfig?.typed_config) {
5057
continue;
5158
}
5259
const typeUrl = extensionConfig.typed_config.type_url;
60+
trace('Attempting to parse config with type_url=' + typeUrl);
61+
let parseResult: LoadBalancingConfig | null;
5362
if (typeUrl in registry) {
5463
try {
55-
return registry[typeUrl].convertToLoadBalancingPolicy(extensionConfig, childPolicy => convertToLoadBalancingConfig(childPolicy, recursionDepth + 1));
64+
parseResult = registry[typeUrl].convertToLoadBalancingPolicy(extensionConfig, childPolicy => convertToLoadBalancingConfig(childPolicy, recursionDepth + 1));
5665
} catch (e) {
57-
throw new Error(`Error parsing ${typeUrl} LoadBalancingPolicy: ${(e as Error).message}`);
66+
throw new Error(`Error parsing ${typeUrl} LoadBalancingPolicy named ${extensionConfig.name}: ${(e as Error).message}`);
67+
}
68+
if (parseResult) {
69+
return parseResult;
70+
} else {
71+
continue;
5872
}
5973
}
6074
}

packages/grpc-js-xds/src/lb-policy-registry/round-robin.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { LoadBalancingPolicy__Output } from "../generated/envoy/config/cluster/v
2020
import { TypedExtensionConfig__Output } from "../generated/envoy/config/core/v3/TypedExtensionConfig";
2121
import { registerLbPolicy } from "../lb-policy-registry";
2222

23-
const ROUND_ROBIN_TYPE_URL = 'envoy.extensions.load_balancing_policies.round_robin.v3.RoundRobin';
23+
const ROUND_ROBIN_TYPE_URL = 'type.googleapis.com/envoy.extensions.load_balancing_policies.round_robin.v3.RoundRobin';
2424

2525
function convertToLoadBalancingPolicy(protoPolicy: TypedExtensionConfig__Output, selectChildPolicy: (childPolicy: LoadBalancingPolicy__Output) => LoadBalancingConfig): LoadBalancingConfig {
2626
if (protoPolicy.typed_config?.type_url !== ROUND_ROBIN_TYPE_URL) {

packages/grpc-js-xds/src/lb-policy-registry/typed-struct.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*
1616
*/
1717

18-
import { LoadBalancingConfig } from "@grpc/grpc-js";
18+
import { LoadBalancingConfig, experimental } from "@grpc/grpc-js";
1919
import { LoadBalancingPolicy__Output } from "../generated/envoy/config/cluster/v3/LoadBalancingPolicy";
2020
import { TypedExtensionConfig__Output } from "../generated/envoy/config/core/v3/TypedExtensionConfig";
2121
import { registerLbPolicy } from "../lb-policy-registry";
@@ -25,16 +25,16 @@ import { Struct__Output } from "../generated/google/protobuf/Struct";
2525
import { Value__Output } from "../generated/google/protobuf/Value";
2626
import { TypedStruct__Output } from "../generated/xds/type/v3/TypedStruct";
2727

28-
const XDS_TYPED_STRUCT_TYPE_URL = 'xds.type.v3.TypedStruct';
29-
const UDPA_TYPED_STRUCT_TYPE_URL = 'udpa.type.v1.TypedStruct';
28+
const XDS_TYPED_STRUCT_TYPE_URL = 'type.googleapis.com/xds.type.v3.TypedStruct';
29+
const UDPA_TYPED_STRUCT_TYPE_URL = 'type.googleapis.com/udpa.type.v1.TypedStruct';
3030

3131
const resourceRoot = loadProtosWithOptionsSync([
3232
'xds/type/v3/typed_struct.proto',
3333
'udpa/type/v1/typed_struct.proto'], {
3434
keepCase: true,
3535
includeDirs: [
36-
// Paths are relative to src/build
37-
__dirname + '/../../deps/xds/',
36+
// Paths are relative to src/build/lb-policy-registry
37+
__dirname + '/../../../deps/xds/',
3838
],
3939
}
4040
);
@@ -90,7 +90,7 @@ function flattenStruct(struct: Struct__Output): FlatStruct {
9090
return result;
9191
}
9292

93-
function convertToLoadBalancingPolicy(protoPolicy: TypedExtensionConfig__Output, selectChildPolicy: (childPolicy: LoadBalancingPolicy__Output) => LoadBalancingConfig): LoadBalancingConfig {
93+
function convertToLoadBalancingPolicy(protoPolicy: TypedExtensionConfig__Output, selectChildPolicy: (childPolicy: LoadBalancingPolicy__Output) => LoadBalancingConfig): LoadBalancingConfig | null {
9494
if (protoPolicy.typed_config?.type_url !== XDS_TYPED_STRUCT_TYPE_URL && protoPolicy.typed_config?.type_url !== UDPA_TYPED_STRUCT_TYPE_URL) {
9595
throw new Error(`Typed struct LB policy parsing error: unexpected type URL ${protoPolicy.typed_config?.type_url}`);
9696
}
@@ -99,6 +99,9 @@ function convertToLoadBalancingPolicy(protoPolicy: TypedExtensionConfig__Output,
9999
throw new Error(`Typed struct LB parsing error: unexpected value ${typedStruct.value}`);
100100
}
101101
const policyName = typedStruct.type_url.substring(typedStruct.type_url.lastIndexOf('/') + 1);
102+
if (!experimental.isLoadBalancerNameRegistered(policyName)) {
103+
return null;
104+
}
102105
return {
103106
[policyName]: flattenStruct(typedStruct.value)
104107
};

packages/grpc-js-xds/src/load-balancer-xds-wrr-locality.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,14 +113,14 @@ class XdsWrrLocalityLoadBalancer implements LoadBalancer {
113113
}
114114
}
115115

116-
const WRR_LOCALITY_TYPE_URL = 'envoy.extensions.load_balancing_policies.wrr_locality.v3.WrrLocality';
116+
const WRR_LOCALITY_TYPE_URL = 'type.googleapis.com/envoy.extensions.load_balancing_policies.wrr_locality.v3.WrrLocality';
117117

118118
const resourceRoot = loadProtosWithOptionsSync([
119-
'xds/type/v3/typed_struct.proto',
120-
'udpa/type/v1/typed_struct.proto'], {
119+
'envoy/extensions/load_balancing_policies/wrr_locality/v3/wrr_locality.proto'], {
121120
keepCase: true,
122121
includeDirs: [
123122
// Paths are relative to src/build
123+
__dirname + '/../../deps/envoy-api/',
124124
__dirname + '/../../deps/xds/',
125125
__dirname + '/../../deps/protoc-gen-validate'
126126
],
@@ -155,7 +155,7 @@ function convertToLoadBalancingPolicy(protoPolicy: TypedExtensionConfig__Output,
155155
}
156156
return {
157157
[TYPE_NAME]: {
158-
child_policy: selectChildPolicy(wrrLocalityMessage.endpoint_picking_policy)
158+
child_policy: [selectChildPolicy(wrrLocalityMessage.endpoint_picking_policy)]
159159
}
160160
};
161161
}

packages/grpc-js-xds/src/xds-resource-type/cluster-resource-type.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
import { CDS_TYPE_URL, CLUSTER_CONFIG_TYPE_URL, decodeSingleResource } from "../resources";
1919
import { XdsDecodeContext, XdsDecodeResult, XdsResourceType } from "./xds-resource-type";
20-
import { LoadBalancingConfig, experimental } from "@grpc/grpc-js";
20+
import { LoadBalancingConfig, experimental, logVerbosity } from "@grpc/grpc-js";
2121
import { XdsServerConfig } from "../xds-bootstrap";
2222
import { Duration__Output } from "../generated/google/protobuf/Duration";
2323
import { OutlierDetection__Output } from "../generated/envoy/config/cluster/v3/OutlierDetection";
@@ -32,6 +32,13 @@ import SuccessRateEjectionConfig = experimental.SuccessRateEjectionConfig;
3232
import FailurePercentageEjectionConfig = experimental.FailurePercentageEjectionConfig;
3333
import parseLoadBalancingConfig = experimental.parseLoadBalancingConfig;
3434

35+
const TRACER_NAME = 'xds_client';
36+
37+
function trace(text: string): void {
38+
experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text);
39+
}
40+
41+
3542
export interface CdsUpdate {
3643
type: 'AGGREGATE' | 'EDS' | 'LOGICAL_DNS';
3744
name: string;
@@ -128,11 +135,13 @@ export class ClusterResourceType extends XdsResourceType {
128135
try {
129136
lbPolicyConfig = convertToLoadBalancingConfig(message.load_balancing_policy);
130137
} catch (e) {
138+
trace('LB policy config parsing failed with error ' + e);
131139
return null;
132140
}
133141
try {
134142
parseLoadBalancingConfig(lbPolicyConfig);
135143
} catch (e) {
144+
trace('LB policy config parsing failed with error ' + e);
136145
return null;
137146
}
138147
} else if (message.lb_policy === 'ROUND_ROBIN') {

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

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import { CLUSTER_CONFIG_TYPE_URL, HTTP_CONNECTION_MANGER_TYPE_URL } from "../src
2828
import { LocalityLbEndpoints } from "../src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints";
2929
import { LbEndpoint } from "../src/generated/envoy/config/endpoint/v3/LbEndpoint";
3030
import { ClusterConfig } from "../src/generated/envoy/extensions/clusters/aggregate/v3/ClusterConfig";
31+
import { Any } from "../src/generated/google/protobuf/Any";
3132

3233
interface Endpoint {
3334
locality: Locality;
@@ -69,7 +70,7 @@ export interface FakeCluster {
6970
}
7071

7172
export class FakeEdsCluster implements FakeCluster {
72-
constructor(private clusterName: string, private endpointName: string, private endpoints: Endpoint[]) {}
73+
constructor(private clusterName: string, private endpointName: string, private endpoints: Endpoint[], private loadBalancingPolicyOverride?: Any) {}
7374

7475
getEndpointConfig(): ClusterLoadAssignment {
7576
return {
@@ -79,11 +80,10 @@ export class FakeEdsCluster implements FakeCluster {
7980
}
8081

8182
getClusterConfig(): Cluster {
82-
return {
83+
const result: Cluster = {
8384
name: this.clusterName,
8485
type: 'EDS',
8586
eds_cluster_config: {eds_config: {ads: {}}, service_name: this.endpointName},
86-
lb_policy: 'ROUND_ROBIN',
8787
lrs_server: {self: {}},
8888
circuit_breakers: {
8989
thresholds: [
@@ -93,7 +93,22 @@ export class FakeEdsCluster implements FakeCluster {
9393
}
9494
]
9595
}
96+
};
97+
if (this.loadBalancingPolicyOverride) {
98+
result.load_balancing_policy = {
99+
policies: [
100+
{
101+
typed_extension_config: {
102+
'name': 'test',
103+
typed_config: this.loadBalancingPolicyOverride
104+
}
105+
}
106+
]
107+
}
108+
} else {
109+
result.lb_policy = 'ROUND_ROBIN';
96110
}
111+
return result;
97112
}
98113

99114
getAllClusterConfigs(): Cluster[] {

0 commit comments

Comments
 (0)