diff --git a/.gitmodules b/.gitmodules index 18d3c0c8..d3c1ebaf 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,15 +7,15 @@ [submodule "packages/proto-loader/deps/googleapis"] path = packages/proto-loader/deps/googleapis url = https://github.com/googleapis/googleapis.git -[submodule "packages/grpc-js/deps/envoy-api"] - path = packages/grpc-js/deps/envoy-api +[submodule "packages/grpc-js-xds/deps/envoy-api"] + path = packages/grpc-js-xds/deps/envoy-api url = https://github.com/envoyproxy/data-plane-api.git -[submodule "packages/grpc-js/deps/udpa"] - path = packages/grpc-js/deps/udpa +[submodule "packages/grpc-js-xds/deps/udpa"] + path = packages/grpc-js-xds/deps/udpa url = https://github.com/cncf/udpa.git -[submodule "packages/grpc-js/deps/googleapis"] - path = packages/grpc-js/deps/googleapis +[submodule "packages/grpc-js-xds/deps/googleapis"] + path = packages/grpc-js-xds/deps/googleapis url = https://github.com/googleapis/googleapis.git -[submodule "packages/grpc-js/deps/protoc-gen-validate"] - path = packages/grpc-js/deps/protoc-gen-validate +[submodule "packages/grpc-js-xds/deps/protoc-gen-validate"] + path = packages/grpc-js-xds/deps/protoc-gen-validate url = https://github.com/envoyproxy/protoc-gen-validate.git diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index 8bea1fd0..fa0ea319 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -36,6 +36,7 @@ In addition, all channel arguments defined in [this header file](https://github. - `grpc.default_authority` - `grpc.keepalive_time_ms` - `grpc.keepalive_timeout_ms` + - `grpc.keepalive_permit_without_calls` - `grpc.service_config` - `grpc.max_concurrent_streams` - `grpc.initial_reconnect_backoff_ms` diff --git a/gulpfile.ts b/gulpfile.ts index 367b4d1b..7ac4e9a0 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -18,28 +18,29 @@ import * as gulp from 'gulp'; import * as healthCheck from './packages/grpc-health-check/gulpfile'; import * as jsCore from './packages/grpc-js/gulpfile'; +import * as jsXds from './packages/grpc-js-xds/gulpfile'; import * as protobuf from './packages/proto-loader/gulpfile'; import * as internalTest from './test/gulpfile'; -const installAll = gulp.series(jsCore.install, healthCheck.install, protobuf.install, internalTest.install); +const installAll = gulp.series(jsCore.install, healthCheck.install, protobuf.install, internalTest.install, jsXds.install); const lint = gulp.parallel(jsCore.lint); -const build = gulp.series(jsCore.compile, protobuf.compile); +const build = gulp.series(jsCore.compile, protobuf.compile, jsXds.compile); const setup = gulp.series(installAll); const setupPureJSInterop = gulp.series(jsCore.install, protobuf.install, internalTest.install); -const clean = gulp.series(jsCore.clean, protobuf.clean); +const clean = gulp.series(jsCore.clean, protobuf.clean, jsXds.clean); -const cleanAll = gulp.series(jsCore.cleanAll, internalTest.cleanAll, protobuf.cleanAll); +const cleanAll = gulp.series(jsXds.cleanAll, jsCore.cleanAll, internalTest.cleanAll, protobuf.cleanAll); const nativeTestOnly = gulp.parallel(healthCheck.test); const nativeTest = gulp.series(build, nativeTestOnly); -const testOnly = gulp.parallel(jsCore.test, nativeTestOnly, protobuf.test); +const testOnly = gulp.parallel(jsCore.test, nativeTestOnly, protobuf.test, jsXds.test); const test = gulp.series(build, testOnly, internalTest.test); diff --git a/packages/grpc-js-xds/.eslintrc.json b/packages/grpc-js-xds/.eslintrc.json new file mode 100644 index 00000000..f95bb333 --- /dev/null +++ b/packages/grpc-js-xds/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/gts/" +} diff --git a/packages/grpc-js-xds/.prettierrc.js b/packages/grpc-js-xds/.prettierrc.js new file mode 100644 index 00000000..c634ea72 --- /dev/null +++ b/packages/grpc-js-xds/.prettierrc.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('gts/.prettierrc.json') +} \ No newline at end of file diff --git a/packages/grpc-js-xds/README.md b/packages/grpc-js-xds/README.md new file mode 100644 index 00000000..2ada0bad --- /dev/null +++ b/packages/grpc-js-xds/README.md @@ -0,0 +1,24 @@ +# @grpc/grpc-js xDS plugin + +This package provides support for the `xds://` URL scheme to the `@grpc/grpc-js` library. The latest version of this package is compatible with `@grpc/grpc-js` version 1.2.x. + +## Installation + +``` +npm install @grpc/grpc-js-xds +``` + +## Usage + +```ts +import * as grpcJsXds from '@grpc/grpc-js-xds'; +grpcJsXds.register(); + +// ...get a @grpc/grpc-js Client class as usual + +const client = new MyServiceClient('xds:///example.com:123'); +``` + +## Supported Features + + - [xDS-Based Global Load Balancing](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) \ No newline at end of file diff --git a/packages/grpc-js/deps/envoy-api b/packages/grpc-js-xds/deps/envoy-api similarity index 100% rename from packages/grpc-js/deps/envoy-api rename to packages/grpc-js-xds/deps/envoy-api diff --git a/packages/grpc-js/deps/googleapis b/packages/grpc-js-xds/deps/googleapis similarity index 100% rename from packages/grpc-js/deps/googleapis rename to packages/grpc-js-xds/deps/googleapis diff --git a/packages/grpc-js/deps/protoc-gen-validate b/packages/grpc-js-xds/deps/protoc-gen-validate similarity index 100% rename from packages/grpc-js/deps/protoc-gen-validate rename to packages/grpc-js-xds/deps/protoc-gen-validate diff --git a/packages/grpc-js/deps/udpa b/packages/grpc-js-xds/deps/udpa similarity index 100% rename from packages/grpc-js/deps/udpa rename to packages/grpc-js-xds/deps/udpa diff --git a/packages/grpc-js-xds/gulpfile.ts b/packages/grpc-js-xds/gulpfile.ts new file mode 100644 index 00000000..4ee6ac2c --- /dev/null +++ b/packages/grpc-js-xds/gulpfile.ts @@ -0,0 +1,78 @@ +/* + * Copyright 2020 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. + * + */ + +import * as gulp from 'gulp'; + +import * as mocha from 'gulp-mocha'; +import * as path from 'path'; +import * as execa from 'execa'; +import * as semver from 'semver'; + +Error.stackTraceLimit = Infinity; + +const jsCoreDir = __dirname; +const outDir = path.resolve(jsCoreDir, 'build'); + +const pkgPath = path.resolve(jsCoreDir, 'package.json'); +const supportedVersionRange = require(pkgPath).engines.node; +const versionNotSupported = () => { + console.log(`Skipping grpc-js-xds task for Node ${process.version}`); + return () => { return Promise.resolve(); }; +}; +const identity = (value: any): any => value; +const checkTask = semver.satisfies(process.version, supportedVersionRange) ? + identity : versionNotSupported; + +const execNpmVerb = (verb: string, ...args: string[]) => + execa('npm', [verb, ...args], {cwd: jsCoreDir, stdio: 'inherit'}); +const execNpmCommand = execNpmVerb.bind(null, 'run'); + +const install = checkTask(() => execNpmVerb('install', '--unsafe-perm')); + +/** + * Runs tslint on files in src/, with linting rules defined in tslint.json. + */ +const lint = checkTask(() => execNpmCommand('check')); + +const cleanFiles = checkTask(() => execNpmCommand('clean')); + +const clean = gulp.series(install, cleanFiles); + +const cleanAll = gulp.parallel(clean); + +/** + * Transpiles TypeScript files in src/ to JavaScript according to the settings + * found in tsconfig.json. + */ +const compile = checkTask(() => execNpmCommand('compile')); + +const runTests = checkTask(() => { + return gulp.src(`${outDir}/test/**/*.js`) + .pipe(mocha({reporter: 'mocha-jenkins-reporter', + require: ['ts-node/register']})); +}); + +const test = gulp.series(install, runTests); + +export { + install, + lint, + clean, + cleanAll, + compile, + test +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/BoolValue.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/BoolValue.ts new file mode 100644 index 00000000..a1e31ab3 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/BoolValue.ts @@ -0,0 +1,26 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * TODO(dgq): Go back to using well-known types once + * https://github.com/grpc/grpc/issues/6980 has been fixed. + * import "google/protobuf/wrappers.proto"; + */ +export interface BoolValue { + /** + * The bool value. + */ + 'value'?: (boolean); +} + +/** + * TODO(dgq): Go back to using well-known types once + * https://github.com/grpc/grpc/issues/6980 has been fixed. + * import "google/protobuf/wrappers.proto"; + */ +export interface BoolValue__Output { + /** + * The bool value. + */ + 'value': (boolean); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/EchoStatus.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/EchoStatus.ts new file mode 100644 index 00000000..d5da7501 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/EchoStatus.ts @@ -0,0 +1,20 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * A protobuf representation for grpc status. This is used by test + * clients to specify a status that the server should attempt to return. + */ +export interface EchoStatus { + 'code'?: (number); + 'message'?: (string); +} + +/** + * A protobuf representation for grpc status. This is used by test + * clients to specify a status that the server should attempt to return. + */ +export interface EchoStatus__Output { + 'code': (number); + 'message': (string); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/Empty.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/Empty.ts new file mode 100644 index 00000000..d79db52b --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/Empty.ts @@ -0,0 +1,26 @@ +// Original file: proto/grpc/testing/empty.proto + + +/** + * An empty message that you can re-use to avoid defining duplicated empty + * messages in your project. A typical example is to use it as argument or the + * return value of a service API. For instance: + * + * service Foo { + * rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; + * }; + */ +export interface Empty { +} + +/** + * An empty message that you can re-use to avoid defining duplicated empty + * messages in your project. A typical example is to use it as argument or the + * return value of a service API. For instance: + * + * service Foo { + * rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; + * }; + */ +export interface Empty__Output { +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/GrpclbRouteType.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/GrpclbRouteType.ts new file mode 100644 index 00000000..8ab0146b --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/GrpclbRouteType.ts @@ -0,0 +1,24 @@ +// Original file: proto/grpc/testing/messages.proto + +/** + * The type of route that a client took to reach a server w.r.t. gRPCLB. + * The server must fill in "fallback" if it detects that the RPC reached + * the server via the "gRPCLB fallback" path, and "backend" if it detects + * that the RPC reached the server via "gRPCLB backend" path (i.e. if it got + * the address of this server from the gRPCLB server BalanceLoad RPC). Exactly + * how this detection is done is context and server dependent. + */ +export enum GrpclbRouteType { + /** + * Server didn't detect the route that a client took to reach it. + */ + GRPCLB_ROUTE_TYPE_UNKNOWN = 0, + /** + * Indicates that a client reached a server via gRPCLB fallback. + */ + GRPCLB_ROUTE_TYPE_FALLBACK = 1, + /** + * Indicates that a client reached a server as a gRPCLB-given backend. + */ + GRPCLB_ROUTE_TYPE_BACKEND = 2, +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts new file mode 100644 index 00000000..189d871b --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts @@ -0,0 +1,24 @@ +// Original file: proto/grpc/testing/messages.proto + + +export interface LoadBalancerStatsRequest { + /** + * Request stats for the next num_rpcs sent by client. + */ + 'num_rpcs'?: (number); + /** + * If num_rpcs have not completed within timeout_sec, return partial results. + */ + 'timeout_sec'?: (number); +} + +export interface LoadBalancerStatsRequest__Output { + /** + * Request stats for the next num_rpcs sent by client. + */ + 'num_rpcs': (number); + /** + * If num_rpcs have not completed within timeout_sec, return partial results. + */ + 'timeout_sec': (number); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts new file mode 100644 index 00000000..184a6e25 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts @@ -0,0 +1,40 @@ +// Original file: proto/grpc/testing/messages.proto + + +export interface _grpc_testing_LoadBalancerStatsResponse_RpcsByPeer { + /** + * The number of completed RPCs for each peer. + */ + 'rpcs_by_peer'?: ({[key: string]: number}); +} + +export interface _grpc_testing_LoadBalancerStatsResponse_RpcsByPeer__Output { + /** + * The number of completed RPCs for each peer. + */ + 'rpcs_by_peer': ({[key: string]: number}); +} + +export interface LoadBalancerStatsResponse { + /** + * The number of completed RPCs for each peer. + */ + 'rpcs_by_peer'?: ({[key: string]: number}); + /** + * The number of RPCs that failed to record a remote peer. + */ + 'num_failures'?: (number); + 'rpcs_by_method'?: ({[key: string]: _grpc_testing_LoadBalancerStatsResponse_RpcsByPeer}); +} + +export interface LoadBalancerStatsResponse__Output { + /** + * The number of completed RPCs for each peer. + */ + 'rpcs_by_peer': ({[key: string]: number}); + /** + * The number of RPCs that failed to record a remote peer. + */ + 'num_failures': (number); + 'rpcs_by_method'?: ({[key: string]: _grpc_testing_LoadBalancerStatsResponse_RpcsByPeer__Output}); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts new file mode 100644 index 00000000..aa4f409f --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts @@ -0,0 +1,37 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '@grpc/grpc-js' +import { LoadBalancerStatsRequest as _grpc_testing_LoadBalancerStatsRequest, LoadBalancerStatsRequest__Output as _grpc_testing_LoadBalancerStatsRequest__Output } from '../../grpc/testing/LoadBalancerStatsRequest'; +import { LoadBalancerStatsResponse as _grpc_testing_LoadBalancerStatsResponse, LoadBalancerStatsResponse__Output as _grpc_testing_LoadBalancerStatsResponse__Output } from '../../grpc/testing/LoadBalancerStatsResponse'; + +/** + * A service used to obtain stats for verifying LB behavior. + */ +export interface LoadBalancerStatsServiceClient extends grpc.Client { + /** + * Gets the backend distribution for RPCs sent by a test client. + */ + GetClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + GetClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + GetClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + GetClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Gets the backend distribution for RPCs sent by a test client. + */ + getClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + getClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + getClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + getClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * A service used to obtain stats for verifying LB behavior. + */ +export interface LoadBalancerStatsServiceHandlers extends grpc.UntypedServiceImplementation { + /** + * Gets the backend distribution for RPCs sent by a test client. + */ + GetClientStats(call: grpc.ServerUnaryCall<_grpc_testing_LoadBalancerStatsRequest__Output, _grpc_testing_LoadBalancerStatsResponse>, callback: grpc.sendUnaryData<_grpc_testing_LoadBalancerStatsResponse>): void; + +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/Payload.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/Payload.ts new file mode 100644 index 00000000..87fc0cf3 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/Payload.ts @@ -0,0 +1,31 @@ +// Original file: proto/grpc/testing/messages.proto + +import { PayloadType as _grpc_testing_PayloadType } from '../../grpc/testing/PayloadType'; + +/** + * A block of data, to simply increase gRPC message size. + */ +export interface Payload { + /** + * The type of data in body. + */ + 'type'?: (_grpc_testing_PayloadType | keyof typeof _grpc_testing_PayloadType); + /** + * Primary contents of payload. + */ + 'body'?: (Buffer | Uint8Array | string); +} + +/** + * A block of data, to simply increase gRPC message size. + */ +export interface Payload__Output { + /** + * The type of data in body. + */ + 'type': (keyof typeof _grpc_testing_PayloadType); + /** + * Primary contents of payload. + */ + 'body': (Buffer); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/PayloadType.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/PayloadType.ts new file mode 100644 index 00000000..3cf9d375 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/PayloadType.ts @@ -0,0 +1,11 @@ +// Original file: proto/grpc/testing/messages.proto + +/** + * The type of payload that should be returned. + */ +export enum PayloadType { + /** + * Compressable text format. + */ + COMPRESSABLE = 0, +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectInfo.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectInfo.ts new file mode 100644 index 00000000..616de9eb --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectInfo.ts @@ -0,0 +1,22 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * For reconnect interop test only. + * Server tells client whether its reconnects are following the spec and the + * reconnect backoffs it saw. + */ +export interface ReconnectInfo { + 'passed'?: (boolean); + 'backoff_ms'?: (number)[]; +} + +/** + * For reconnect interop test only. + * Server tells client whether its reconnects are following the spec and the + * reconnect backoffs it saw. + */ +export interface ReconnectInfo__Output { + 'passed': (boolean); + 'backoff_ms': (number)[]; +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectParams.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectParams.ts new file mode 100644 index 00000000..1337b568 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectParams.ts @@ -0,0 +1,18 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * For reconnect interop test only. + * Client tells server what reconnection parameters it used. + */ +export interface ReconnectParams { + 'max_reconnect_backoff_ms'?: (number); +} + +/** + * For reconnect interop test only. + * Client tells server what reconnection parameters it used. + */ +export interface ReconnectParams__Output { + 'max_reconnect_backoff_ms': (number); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts new file mode 100644 index 00000000..21114765 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts @@ -0,0 +1,40 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '@grpc/grpc-js' +import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; +import { ReconnectInfo as _grpc_testing_ReconnectInfo, ReconnectInfo__Output as _grpc_testing_ReconnectInfo__Output } from '../../grpc/testing/ReconnectInfo'; +import { ReconnectParams as _grpc_testing_ReconnectParams, ReconnectParams__Output as _grpc_testing_ReconnectParams__Output } from '../../grpc/testing/ReconnectParams'; + +/** + * A service used to control reconnect server. + */ +export interface ReconnectServiceClient extends grpc.Client { + Start(argument: _grpc_testing_ReconnectParams, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + Start(argument: _grpc_testing_ReconnectParams, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + Start(argument: _grpc_testing_ReconnectParams, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + Start(argument: _grpc_testing_ReconnectParams, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + start(argument: _grpc_testing_ReconnectParams, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + start(argument: _grpc_testing_ReconnectParams, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + start(argument: _grpc_testing_ReconnectParams, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + start(argument: _grpc_testing_ReconnectParams, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + + Stop(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + Stop(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + Stop(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + Stop(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + stop(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + stop(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + stop(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + stop(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * A service used to control reconnect server. + */ +export interface ReconnectServiceHandlers extends grpc.UntypedServiceImplementation { + Start(call: grpc.ServerUnaryCall<_grpc_testing_ReconnectParams__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + + Stop(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_ReconnectInfo>, callback: grpc.sendUnaryData<_grpc_testing_ReconnectInfo>): void; + +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/ResponseParameters.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ResponseParameters.ts new file mode 100644 index 00000000..9bd24ee3 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/ResponseParameters.ts @@ -0,0 +1,47 @@ +// Original file: proto/grpc/testing/messages.proto + +import { BoolValue as _grpc_testing_BoolValue, BoolValue__Output as _grpc_testing_BoolValue__Output } from '../../grpc/testing/BoolValue'; + +/** + * Configuration for a particular response. + */ +export interface ResponseParameters { + /** + * Desired payload sizes in responses from the server. + */ + 'size'?: (number); + /** + * Desired interval between consecutive responses in the response stream in + * microseconds. + */ + 'interval_us'?: (number); + /** + * Whether to request the server to compress the response. This field is + * "nullable" in order to interoperate seamlessly with clients not able to + * implement the full compression tests by introspecting the call to verify + * the response's compression status. + */ + 'compressed'?: (_grpc_testing_BoolValue); +} + +/** + * Configuration for a particular response. + */ +export interface ResponseParameters__Output { + /** + * Desired payload sizes in responses from the server. + */ + 'size': (number); + /** + * Desired interval between consecutive responses in the response stream in + * microseconds. + */ + 'interval_us': (number); + /** + * Whether to request the server to compress the response. This field is + * "nullable" in order to interoperate seamlessly with clients not able to + * implement the full compression tests by introspecting the call to verify + * the response's compression status. + */ + 'compressed'?: (_grpc_testing_BoolValue__Output); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleRequest.ts new file mode 100644 index 00000000..b03f6f6d --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleRequest.ts @@ -0,0 +1,106 @@ +// Original file: proto/grpc/testing/messages.proto + +import { PayloadType as _grpc_testing_PayloadType } from '../../grpc/testing/PayloadType'; +import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import { BoolValue as _grpc_testing_BoolValue, BoolValue__Output as _grpc_testing_BoolValue__Output } from '../../grpc/testing/BoolValue'; +import { EchoStatus as _grpc_testing_EchoStatus, EchoStatus__Output as _grpc_testing_EchoStatus__Output } from '../../grpc/testing/EchoStatus'; + +/** + * Unary request. + */ +export interface SimpleRequest { + /** + * Desired payload type in the response from the server. + * If response_type is RANDOM, server randomly chooses one from other formats. + */ + 'response_type'?: (_grpc_testing_PayloadType | keyof typeof _grpc_testing_PayloadType); + /** + * Desired payload size in the response from the server. + */ + 'response_size'?: (number); + /** + * Optional input payload sent along with the request. + */ + 'payload'?: (_grpc_testing_Payload); + /** + * Whether SimpleResponse should include username. + */ + 'fill_username'?: (boolean); + /** + * Whether SimpleResponse should include OAuth scope. + */ + 'fill_oauth_scope'?: (boolean); + /** + * Whether to request the server to compress the response. This field is + * "nullable" in order to interoperate seamlessly with clients not able to + * implement the full compression tests by introspecting the call to verify + * the response's compression status. + */ + 'response_compressed'?: (_grpc_testing_BoolValue); + /** + * Whether server should return a given status + */ + 'response_status'?: (_grpc_testing_EchoStatus); + /** + * Whether the server should expect this request to be compressed. + */ + 'expect_compressed'?: (_grpc_testing_BoolValue); + /** + * Whether SimpleResponse should include server_id. + */ + 'fill_server_id'?: (boolean); + /** + * Whether SimpleResponse should include grpclb_route_type. + */ + 'fill_grpclb_route_type'?: (boolean); +} + +/** + * Unary request. + */ +export interface SimpleRequest__Output { + /** + * Desired payload type in the response from the server. + * If response_type is RANDOM, server randomly chooses one from other formats. + */ + 'response_type': (keyof typeof _grpc_testing_PayloadType); + /** + * Desired payload size in the response from the server. + */ + 'response_size': (number); + /** + * Optional input payload sent along with the request. + */ + 'payload'?: (_grpc_testing_Payload__Output); + /** + * Whether SimpleResponse should include username. + */ + 'fill_username': (boolean); + /** + * Whether SimpleResponse should include OAuth scope. + */ + 'fill_oauth_scope': (boolean); + /** + * Whether to request the server to compress the response. This field is + * "nullable" in order to interoperate seamlessly with clients not able to + * implement the full compression tests by introspecting the call to verify + * the response's compression status. + */ + 'response_compressed'?: (_grpc_testing_BoolValue__Output); + /** + * Whether server should return a given status + */ + 'response_status'?: (_grpc_testing_EchoStatus__Output); + /** + * Whether the server should expect this request to be compressed. + */ + 'expect_compressed'?: (_grpc_testing_BoolValue__Output); + /** + * Whether SimpleResponse should include server_id. + */ + 'fill_server_id': (boolean); + /** + * Whether SimpleResponse should include grpclb_route_type. + */ + 'fill_grpclb_route_type': (boolean); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleResponse.ts new file mode 100644 index 00000000..7a96e7df --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleResponse.ts @@ -0,0 +1,68 @@ +// Original file: proto/grpc/testing/messages.proto + +import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import { GrpclbRouteType as _grpc_testing_GrpclbRouteType } from '../../grpc/testing/GrpclbRouteType'; + +/** + * Unary response, as configured by the request. + */ +export interface SimpleResponse { + /** + * Payload to increase message size. + */ + 'payload'?: (_grpc_testing_Payload); + /** + * The user the request came from, for verifying authentication was + * successful when the client expected it. + */ + 'username'?: (string); + /** + * OAuth scope. + */ + 'oauth_scope'?: (string); + /** + * Server ID. This must be unique among different server instances, + * but the same across all RPC's made to a particular server instance. + */ + 'server_id'?: (string); + /** + * gRPCLB Path. + */ + 'grpclb_route_type'?: (_grpc_testing_GrpclbRouteType | keyof typeof _grpc_testing_GrpclbRouteType); + /** + * Server hostname. + */ + 'hostname'?: (string); +} + +/** + * Unary response, as configured by the request. + */ +export interface SimpleResponse__Output { + /** + * Payload to increase message size. + */ + 'payload'?: (_grpc_testing_Payload__Output); + /** + * The user the request came from, for verifying authentication was + * successful when the client expected it. + */ + 'username': (string); + /** + * OAuth scope. + */ + 'oauth_scope': (string); + /** + * Server ID. This must be unique among different server instances, + * but the same across all RPC's made to a particular server instance. + */ + 'server_id': (string); + /** + * gRPCLB Path. + */ + 'grpclb_route_type': (keyof typeof _grpc_testing_GrpclbRouteType); + /** + * Server hostname. + */ + 'hostname': (string); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallRequest.ts new file mode 100644 index 00000000..db9d8d40 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallRequest.ts @@ -0,0 +1,38 @@ +// Original file: proto/grpc/testing/messages.proto + +import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import { BoolValue as _grpc_testing_BoolValue, BoolValue__Output as _grpc_testing_BoolValue__Output } from '../../grpc/testing/BoolValue'; + +/** + * Client-streaming request. + */ +export interface StreamingInputCallRequest { + /** + * Optional input payload sent along with the request. + */ + 'payload'?: (_grpc_testing_Payload); + /** + * Whether the server should expect this request to be compressed. This field + * is "nullable" in order to interoperate seamlessly with servers not able to + * implement the full compression tests by introspecting the call to verify + * the request's compression status. + */ + 'expect_compressed'?: (_grpc_testing_BoolValue); +} + +/** + * Client-streaming request. + */ +export interface StreamingInputCallRequest__Output { + /** + * Optional input payload sent along with the request. + */ + 'payload'?: (_grpc_testing_Payload__Output); + /** + * Whether the server should expect this request to be compressed. This field + * is "nullable" in order to interoperate seamlessly with servers not able to + * implement the full compression tests by introspecting the call to verify + * the request's compression status. + */ + 'expect_compressed'?: (_grpc_testing_BoolValue__Output); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallResponse.ts new file mode 100644 index 00000000..1703e755 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallResponse.ts @@ -0,0 +1,22 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * Client-streaming response. + */ +export interface StreamingInputCallResponse { + /** + * Aggregated size of payloads received from the client. + */ + 'aggregated_payload_size'?: (number); +} + +/** + * Client-streaming response. + */ +export interface StreamingInputCallResponse__Output { + /** + * Aggregated size of payloads received from the client. + */ + 'aggregated_payload_size': (number); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallRequest.ts new file mode 100644 index 00000000..0d7bff2f --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallRequest.ts @@ -0,0 +1,56 @@ +// Original file: proto/grpc/testing/messages.proto + +import { PayloadType as _grpc_testing_PayloadType } from '../../grpc/testing/PayloadType'; +import { ResponseParameters as _grpc_testing_ResponseParameters, ResponseParameters__Output as _grpc_testing_ResponseParameters__Output } from '../../grpc/testing/ResponseParameters'; +import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import { EchoStatus as _grpc_testing_EchoStatus, EchoStatus__Output as _grpc_testing_EchoStatus__Output } from '../../grpc/testing/EchoStatus'; + +/** + * Server-streaming request. + */ +export interface StreamingOutputCallRequest { + /** + * Desired payload type in the response from the server. + * If response_type is RANDOM, the payload from each response in the stream + * might be of different types. This is to simulate a mixed type of payload + * stream. + */ + 'response_type'?: (_grpc_testing_PayloadType | keyof typeof _grpc_testing_PayloadType); + /** + * Configuration for each expected response message. + */ + 'response_parameters'?: (_grpc_testing_ResponseParameters)[]; + /** + * Optional input payload sent along with the request. + */ + 'payload'?: (_grpc_testing_Payload); + /** + * Whether server should return a given status + */ + 'response_status'?: (_grpc_testing_EchoStatus); +} + +/** + * Server-streaming request. + */ +export interface StreamingOutputCallRequest__Output { + /** + * Desired payload type in the response from the server. + * If response_type is RANDOM, the payload from each response in the stream + * might be of different types. This is to simulate a mixed type of payload + * stream. + */ + 'response_type': (keyof typeof _grpc_testing_PayloadType); + /** + * Configuration for each expected response message. + */ + 'response_parameters': (_grpc_testing_ResponseParameters__Output)[]; + /** + * Optional input payload sent along with the request. + */ + 'payload'?: (_grpc_testing_Payload__Output); + /** + * Whether server should return a given status + */ + 'response_status'?: (_grpc_testing_EchoStatus__Output); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallResponse.ts new file mode 100644 index 00000000..9b8f49e3 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallResponse.ts @@ -0,0 +1,23 @@ +// Original file: proto/grpc/testing/messages.proto + +import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; + +/** + * Server-streaming response, as configured by the request and parameters. + */ +export interface StreamingOutputCallResponse { + /** + * Payload to increase response size. + */ + 'payload'?: (_grpc_testing_Payload); +} + +/** + * Server-streaming response, as configured by the request and parameters. + */ +export interface StreamingOutputCallResponse__Output { + /** + * Payload to increase response size. + */ + 'payload'?: (_grpc_testing_Payload__Output); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts new file mode 100644 index 00000000..2ccf45fd --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts @@ -0,0 +1,202 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '@grpc/grpc-js' +import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; +import { SimpleRequest as _grpc_testing_SimpleRequest, SimpleRequest__Output as _grpc_testing_SimpleRequest__Output } from '../../grpc/testing/SimpleRequest'; +import { SimpleResponse as _grpc_testing_SimpleResponse, SimpleResponse__Output as _grpc_testing_SimpleResponse__Output } from '../../grpc/testing/SimpleResponse'; +import { StreamingInputCallRequest as _grpc_testing_StreamingInputCallRequest, StreamingInputCallRequest__Output as _grpc_testing_StreamingInputCallRequest__Output } from '../../grpc/testing/StreamingInputCallRequest'; +import { StreamingInputCallResponse as _grpc_testing_StreamingInputCallResponse, StreamingInputCallResponse__Output as _grpc_testing_StreamingInputCallResponse__Output } from '../../grpc/testing/StreamingInputCallResponse'; +import { StreamingOutputCallRequest as _grpc_testing_StreamingOutputCallRequest, StreamingOutputCallRequest__Output as _grpc_testing_StreamingOutputCallRequest__Output } from '../../grpc/testing/StreamingOutputCallRequest'; +import { StreamingOutputCallResponse as _grpc_testing_StreamingOutputCallResponse, StreamingOutputCallResponse__Output as _grpc_testing_StreamingOutputCallResponse__Output } from '../../grpc/testing/StreamingOutputCallResponse'; + +/** + * A simple service to test the various types of RPCs and experiment with + * performance with various types of payload. + */ +export interface TestServiceClient extends grpc.Client { + /** + * One request followed by one response. Response has cache control + * headers set such that a caching HTTP proxy (such as GFE) can + * satisfy subsequent requests. + */ + CacheableUnaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + CacheableUnaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + CacheableUnaryCall(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + CacheableUnaryCall(argument: _grpc_testing_SimpleRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + /** + * One request followed by one response. Response has cache control + * headers set such that a caching HTTP proxy (such as GFE) can + * satisfy subsequent requests. + */ + cacheableUnaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + cacheableUnaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + cacheableUnaryCall(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + cacheableUnaryCall(argument: _grpc_testing_SimpleRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + + /** + * One empty request followed by one empty response. + */ + EmptyCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + EmptyCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + EmptyCall(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + EmptyCall(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + /** + * One empty request followed by one empty response. + */ + emptyCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + emptyCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + emptyCall(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + emptyCall(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + + /** + * A sequence of requests with each request served by the server immediately. + * As one request could lead to multiple responses, this interface + * demonstrates the idea of full duplexing. + */ + FullDuplexCall(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + FullDuplexCall(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + /** + * A sequence of requests with each request served by the server immediately. + * As one request could lead to multiple responses, this interface + * demonstrates the idea of full duplexing. + */ + fullDuplexCall(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + fullDuplexCall(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + + /** + * A sequence of requests followed by a sequence of responses. + * The server buffers all the client requests and then serves them in order. A + * stream of responses are returned to the client when the server starts with + * first request. + */ + HalfDuplexCall(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + HalfDuplexCall(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + /** + * A sequence of requests followed by a sequence of responses. + * The server buffers all the client requests and then serves them in order. A + * stream of responses are returned to the client when the server starts with + * first request. + */ + halfDuplexCall(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + halfDuplexCall(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + + /** + * A sequence of requests followed by one response (streamed upload). + * The server returns the aggregated size of client payload as the result. + */ + StreamingInputCall(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + StreamingInputCall(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + StreamingInputCall(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + StreamingInputCall(callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + /** + * A sequence of requests followed by one response (streamed upload). + * The server returns the aggregated size of client payload as the result. + */ + streamingInputCall(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + streamingInputCall(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + streamingInputCall(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + streamingInputCall(callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + + /** + * One request followed by a sequence of responses (streamed download). + * The server returns the payload with client desired type and sizes. + */ + StreamingOutputCall(argument: _grpc_testing_StreamingOutputCallRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_StreamingOutputCallResponse__Output>; + StreamingOutputCall(argument: _grpc_testing_StreamingOutputCallRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_StreamingOutputCallResponse__Output>; + /** + * One request followed by a sequence of responses (streamed download). + * The server returns the payload with client desired type and sizes. + */ + streamingOutputCall(argument: _grpc_testing_StreamingOutputCallRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_StreamingOutputCallResponse__Output>; + streamingOutputCall(argument: _grpc_testing_StreamingOutputCallRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_StreamingOutputCallResponse__Output>; + + /** + * One request followed by one response. + */ + UnaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + UnaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + UnaryCall(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + UnaryCall(argument: _grpc_testing_SimpleRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + /** + * One request followed by one response. + */ + unaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + unaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + unaryCall(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + unaryCall(argument: _grpc_testing_SimpleRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + + /** + * The test server will not implement this method. It will be used + * to test the behavior when clients call unimplemented methods. + */ + UnimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + UnimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + UnimplementedCall(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + UnimplementedCall(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + /** + * The test server will not implement this method. It will be used + * to test the behavior when clients call unimplemented methods. + */ + unimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + unimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + unimplementedCall(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + unimplementedCall(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * A simple service to test the various types of RPCs and experiment with + * performance with various types of payload. + */ +export interface TestServiceHandlers extends grpc.UntypedServiceImplementation { + /** + * One request followed by one response. Response has cache control + * headers set such that a caching HTTP proxy (such as GFE) can + * satisfy subsequent requests. + */ + CacheableUnaryCall(call: grpc.ServerUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse>, callback: grpc.sendUnaryData<_grpc_testing_SimpleResponse>): void; + + /** + * One empty request followed by one empty response. + */ + EmptyCall(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + + /** + * A sequence of requests with each request served by the server immediately. + * As one request could lead to multiple responses, this interface + * demonstrates the idea of full duplexing. + */ + FullDuplexCall(call: grpc.ServerDuplexStream<_grpc_testing_StreamingOutputCallRequest__Output, _grpc_testing_StreamingOutputCallResponse>): void; + + /** + * A sequence of requests followed by a sequence of responses. + * The server buffers all the client requests and then serves them in order. A + * stream of responses are returned to the client when the server starts with + * first request. + */ + HalfDuplexCall(call: grpc.ServerDuplexStream<_grpc_testing_StreamingOutputCallRequest__Output, _grpc_testing_StreamingOutputCallResponse>): void; + + /** + * A sequence of requests followed by one response (streamed upload). + * The server returns the aggregated size of client payload as the result. + */ + StreamingInputCall(call: grpc.ServerReadableStream<_grpc_testing_StreamingInputCallRequest__Output, _grpc_testing_StreamingInputCallResponse>, callback: grpc.sendUnaryData<_grpc_testing_StreamingInputCallResponse>): void; + + /** + * One request followed by a sequence of responses (streamed download). + * The server returns the payload with client desired type and sizes. + */ + StreamingOutputCall(call: grpc.ServerWritableStream<_grpc_testing_StreamingOutputCallRequest__Output, _grpc_testing_StreamingOutputCallResponse>): void; + + /** + * One request followed by one response. + */ + UnaryCall(call: grpc.ServerUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse>, callback: grpc.sendUnaryData<_grpc_testing_SimpleResponse>): void; + + /** + * The test server will not implement this method. It will be used + * to test the behavior when clients call unimplemented methods. + */ + UnimplementedCall(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts new file mode 100644 index 00000000..121dfa91 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts @@ -0,0 +1,38 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '@grpc/grpc-js' +import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; + +/** + * A simple service NOT implemented at servers so clients can test for + * that case. + */ +export interface UnimplementedServiceClient extends grpc.Client { + /** + * A call that no server should implement + */ + UnimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + UnimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + UnimplementedCall(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + UnimplementedCall(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + /** + * A call that no server should implement + */ + unimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + unimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + unimplementedCall(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + unimplementedCall(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * A simple service NOT implemented at servers so clients can test for + * that case. + */ +export interface UnimplementedServiceHandlers extends grpc.UntypedServiceImplementation { + /** + * A call that no server should implement + */ + UnimplementedCall(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts new file mode 100644 index 00000000..f898a16d --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts @@ -0,0 +1,38 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '@grpc/grpc-js' +import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; + +/** + * A service to remotely control health status of an xDS test server. + */ +export interface XdsUpdateHealthServiceClient extends grpc.Client { + SetNotServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + SetNotServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + SetNotServing(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + SetNotServing(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setNotServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setNotServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setNotServing(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setNotServing(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + + SetServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + SetServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + SetServing(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + SetServing(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setServing(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setServing(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * A service to remotely control health status of an xDS test server. + */ +export interface XdsUpdateHealthServiceHandlers extends grpc.UntypedServiceImplementation { + SetNotServing(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + + SetServing(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + +} diff --git a/packages/grpc-js-xds/interop/generated/test.ts b/packages/grpc-js-xds/interop/generated/test.ts new file mode 100644 index 00000000..330dbc9f --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/test.ts @@ -0,0 +1,60 @@ +import * as grpc from '@grpc/grpc-js'; +import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + +import { LoadBalancerStatsServiceClient as _grpc_testing_LoadBalancerStatsServiceClient } from './grpc/testing/LoadBalancerStatsService'; +import { ReconnectServiceClient as _grpc_testing_ReconnectServiceClient } from './grpc/testing/ReconnectService'; +import { TestServiceClient as _grpc_testing_TestServiceClient } from './grpc/testing/TestService'; +import { UnimplementedServiceClient as _grpc_testing_UnimplementedServiceClient } from './grpc/testing/UnimplementedService'; +import { XdsUpdateHealthServiceClient as _grpc_testing_XdsUpdateHealthServiceClient } from './grpc/testing/XdsUpdateHealthService'; + +type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; +type SubtypeConstructor = { + new(...args: ConstructorArguments): Subtype; +}; + +export interface ProtoGrpcType { + grpc: { + testing: { + BoolValue: MessageTypeDefinition + EchoStatus: MessageTypeDefinition + Empty: MessageTypeDefinition + GrpclbRouteType: EnumTypeDefinition + LoadBalancerStatsRequest: MessageTypeDefinition + LoadBalancerStatsResponse: MessageTypeDefinition + /** + * A service used to obtain stats for verifying LB behavior. + */ + LoadBalancerStatsService: SubtypeConstructor & { service: ServiceDefinition } + Payload: MessageTypeDefinition + PayloadType: EnumTypeDefinition + ReconnectInfo: MessageTypeDefinition + ReconnectParams: MessageTypeDefinition + /** + * A service used to control reconnect server. + */ + ReconnectService: SubtypeConstructor & { service: ServiceDefinition } + ResponseParameters: MessageTypeDefinition + SimpleRequest: MessageTypeDefinition + SimpleResponse: MessageTypeDefinition + StreamingInputCallRequest: MessageTypeDefinition + StreamingInputCallResponse: MessageTypeDefinition + StreamingOutputCallRequest: MessageTypeDefinition + StreamingOutputCallResponse: MessageTypeDefinition + /** + * A simple service to test the various types of RPCs and experiment with + * performance with various types of payload. + */ + TestService: SubtypeConstructor & { service: ServiceDefinition } + /** + * A simple service NOT implemented at servers so clients can test for + * that case. + */ + UnimplementedService: SubtypeConstructor & { service: ServiceDefinition } + /** + * A service to remotely control health status of an xDS test server. + */ + XdsUpdateHealthService: SubtypeConstructor & { service: ServiceDefinition } + } + } +} + diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts new file mode 100644 index 00000000..526c5194 --- /dev/null +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -0,0 +1,253 @@ +/* + * Copyright 2020 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. + * + */ + +import * as grpc from '@grpc/grpc-js'; + +import * as grpc_xds from '../src'; + +import { ProtoGrpcType } from './generated/test'; + +import * as protoLoader from '@grpc/proto-loader'; +import { TestServiceClient } from './generated/grpc/testing/TestService'; +import { LoadBalancerStatsResponse } from './generated/grpc/testing/LoadBalancerStatsResponse'; +import * as yargs from 'yargs'; +import { LoadBalancerStatsServiceHandlers } from './generated/grpc/testing/LoadBalancerStatsService'; + +grpc_xds.register(); + +const packageDefinition = protoLoader.loadSync('grpc/testing/test.proto', { + keepCase: true, + defaults: true, + oneofs: true, + json: true, + longs: String, + enums: String, + includeDirs: [__dirname + '/../../proto'] +}); + +const loadedProto = grpc.loadPackageDefinition(packageDefinition) as unknown as ProtoGrpcType; + +const REQUEST_TIMEOUT_SEC = 20; + +const VERBOSITY = Number.parseInt(process.env.NODE_XDS_INTEROP_VERBOSITY ?? '0'); + +interface CallEndNotifier { + onCallSucceeded(peerName: string): void; + onCallFailed(message: string): void; +} + +class CallSubscriber { + private callsStarted = 0; + private callsSucceededByPeer: {[key: string]: number} = {}; + private callsSucceeded = 0; + private callsFinished = 0; + private failureMessageCount: Map = new Map(); + + constructor(private callGoal: number, private onFinished: () => void) {} + + addCallStarted(): void { + if (VERBOSITY >= 2) { + console.log('Call started'); + } + this.callsStarted += 1; + } + + private maybeOnFinished() { + if (this.callsFinished == this.callGoal) { + this.onFinished(); + } + } + + addCallSucceeded(peerName: string): void { + if (VERBOSITY >= 2) { + console.log(`Call to ${peerName} succeeded`); + } + if (peerName in this.callsSucceededByPeer) { + this.callsSucceededByPeer[peerName] += 1; + } else { + this.callsSucceededByPeer[peerName] = 1; + } + this.callsSucceeded += 1; + this.callsFinished += 1; + this.maybeOnFinished(); + } + addCallFailed(message: string): void { + if (VERBOSITY >= 2) { + console.log(`Call failed with message ${message}`); + } + this.callsFinished += 1; + this.failureMessageCount.set(message, (this.failureMessageCount.get(message) ?? 0) + 1); + this.maybeOnFinished(); + } + + needsMoreCalls(): boolean { + return this.callsStarted < this.callGoal; + } + + getFinalStats(): LoadBalancerStatsResponse { + if (VERBOSITY >= 1) { + console.log(`Out of a total of ${this.callGoal} calls requested, ${this.callsFinished} finished. ${this.callsSucceeded} succeeded`); + for (const [message, count] of this.failureMessageCount) { + console.log(`${count} failed with the message ${message}`); + } + } + return { + rpcs_by_peer: this.callsSucceededByPeer, + num_failures: this.callsStarted - this.callsSucceeded + }; + } +} + +class CallStatsTracker { + + private subscribers: CallSubscriber[] = []; + + getCallStats(callCount: number, timeoutSec: number): Promise { + return new Promise((resolve, reject) => { + let finished = false; + const subscriber = new CallSubscriber(callCount, () => { + if (!finished) { + finished = true; + resolve(subscriber.getFinalStats()); + } + }); + setTimeout(() => { + if (!finished) { + finished = true; + this.subscribers.splice(this.subscribers.indexOf(subscriber), 1); + resolve(subscriber.getFinalStats()); + } + }, timeoutSec * 1000) + this.subscribers.push(subscriber); + }) + } + + startCall(): CallEndNotifier { + const callSubscribers = this.subscribers.slice(); + for (const subscriber of callSubscribers) { + subscriber.addCallStarted(); + if (!subscriber.needsMoreCalls()) { + this.subscribers.splice(this.subscribers.indexOf(subscriber), 1); + } + } + return { + onCallSucceeded: (peerName: string) => { + for (const subscriber of callSubscribers) { + subscriber.addCallSucceeded(peerName); + } + }, + onCallFailed: (message: string) => { + for (const subscriber of callSubscribers) { + subscriber.addCallFailed(message); + } + } + } + } +} + +function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { + let anyCallSucceeded: boolean = false; + setInterval(() => { + const notifier = callStatsTracker.startCall(); + let gotMetadata: boolean = false; + let hostname: string | null = null; + let completed: boolean = false; + let completedWithError: boolean = false; + const deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + REQUEST_TIMEOUT_SEC); + const call = client.emptyCall({}, {deadline}, (error, value) => { + if (error) { + if (failOnFailedRpcs && anyCallSucceeded) { + console.error('A call failed after a call succeeded'); + process.exit(1); + } + completed = true; + completedWithError = true; + notifier.onCallFailed(error.message); + } else { + anyCallSucceeded = true; + if (gotMetadata) { + if (hostname === null) { + notifier.onCallFailed('Hostname omitted from call metadata'); + } else { + notifier.onCallSucceeded(hostname); + } + } + } + }); + call.on('metadata', (metadata) => { + hostname = (metadata.get('hostname') as string[])[0] ?? null; + gotMetadata = true; + if (completed && !completedWithError) { + if (hostname === null) { + notifier.onCallFailed('Hostname omitted from call metadata'); + } else { + notifier.onCallSucceeded(hostname); + } + } + }) + }, 1000/qps); +} + + + +function main() { + const argv = yargs + .string(['fail_on_failed_rpcs', 'server', 'stats_port']) + .number(['num_channels', 'qps']) + .require(['qps', 'server', 'stats_port']) + .default('num_channels', 1) + .argv; + console.log('Starting xDS interop client. Args: ', argv); + const callStatsTracker = new CallStatsTracker(); + for (let i = 0; i < argv.num_channels; i++) { + /* The 'unique' channel argument is there solely to ensure that the + * channels do not share any subchannels. It does not have any + * inherent function. */ + console.log(`Interop client channel ${i} starting sending ${argv.qps} QPS to ${argv.server}`); + sendConstantQps(new loadedProto.grpc.testing.TestService(argv.server, grpc.credentials.createInsecure(), {'unique': i}), + argv.qps, + argv.fail_on_failed_rpcs === 'true', + callStatsTracker); + } + + const loadBalancerStatsServiceImpl: LoadBalancerStatsServiceHandlers = { + GetClientStats: (call, callback) => { + console.log(`Received stats request with num_rpcs=${call.request.num_rpcs} and timeout_sec=${call.request.num_rpcs}`); + callStatsTracker.getCallStats(call.request.num_rpcs, call.request.timeout_sec).then((value) => { + console.log(`Sending stats response: ${JSON.stringify(value)}`); + callback(null, value); + }, (error) => { + callback({code: grpc.status.ABORTED, details: 'Call stats collection failed'}); + }); + } + } + + const server = new grpc.Server(); + server.addService(loadedProto.grpc.testing.LoadBalancerStatsService.service, loadBalancerStatsServiceImpl); + server.bindAsync(`0.0.0.0:${argv.stats_port}`, grpc.ServerCredentials.createInsecure(), (error, port) => { + if (error) { + throw error; + } + console.log(`Starting stats service server bound to port ${port}`); + server.start(); + }); +} + +if (require.main === module) { + main(); +} \ No newline at end of file diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json new file mode 100644 index 00000000..78d90c1d --- /dev/null +++ b/packages/grpc-js-xds/package.json @@ -0,0 +1,53 @@ +{ + "name": "@grpc/grpc-js-xds", + "version": "1.0.0", + "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", + "main": "build/src/index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "check": "gts check", + "clean": "gts clean", + "compile": "tsc", + "fix": "gts fix", + "prepare": "npm run compile", + "pretest": "npm run compile", + "posttest": "npm run check", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto", + "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/grpc/grpc-node.git" + }, + "keywords": [ + "grpc" + ], + "author": { + "name": "Google Inc." + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/grpc/grpc-node/issues" + }, + "homepage": "https://github.com/grpc/grpc-node#readme", + "devDependencies": { + "@grpc/grpc-js": "file:../grpc-js", + "gts": "^2.0.2", + "typescript": "^3.8.3", + "@types/gulp": "^4.0.6", + "@types/gulp-mocha": "0.0.32", + "@types/mocha": "^5.2.6", + "@types/node": "^13.11.1", + "@types/yargs": "^15.0.5", + "yargs": "^15.4.1" + }, + "dependencies": { + "@grpc/proto-loader": "^0.6.0-pre14" + }, + "peerDependencies": { + "@grpc/grpc-js": "~1.2.0" + }, + "engines": { + "node": ">=10.10.0" + } +} diff --git a/packages/grpc-js-xds/proto/grpc/testing/empty.proto b/packages/grpc-js-xds/proto/grpc/testing/empty.proto new file mode 100644 index 00000000..6a0aa88d --- /dev/null +++ b/packages/grpc-js-xds/proto/grpc/testing/empty.proto @@ -0,0 +1,28 @@ + +// Copyright 2015 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. + +syntax = "proto3"; + +package grpc.testing; + +// An empty message that you can re-use to avoid defining duplicated empty +// messages in your project. A typical example is to use it as argument or the +// return value of a service API. For instance: +// +// service Foo { +// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; +// }; +// +message Empty {} diff --git a/packages/grpc-js-xds/proto/grpc/testing/messages.proto b/packages/grpc-js-xds/proto/grpc/testing/messages.proto new file mode 100644 index 00000000..70e34277 --- /dev/null +++ b/packages/grpc-js-xds/proto/grpc/testing/messages.proto @@ -0,0 +1,214 @@ + +// Copyright 2015-2016 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. + +// Message definitions to be used by integration test service definitions. + +syntax = "proto3"; + +package grpc.testing; + +// TODO(dgq): Go back to using well-known types once +// https://github.com/grpc/grpc/issues/6980 has been fixed. +// import "google/protobuf/wrappers.proto"; +message BoolValue { + // The bool value. + bool value = 1; +} + +// The type of payload that should be returned. +enum PayloadType { + // Compressable text format. + COMPRESSABLE = 0; +} + +// A block of data, to simply increase gRPC message size. +message Payload { + // The type of data in body. + PayloadType type = 1; + // Primary contents of payload. + bytes body = 2; +} + +// A protobuf representation for grpc status. This is used by test +// clients to specify a status that the server should attempt to return. +message EchoStatus { + int32 code = 1; + string message = 2; +} + +// The type of route that a client took to reach a server w.r.t. gRPCLB. +// The server must fill in "fallback" if it detects that the RPC reached +// the server via the "gRPCLB fallback" path, and "backend" if it detects +// that the RPC reached the server via "gRPCLB backend" path (i.e. if it got +// the address of this server from the gRPCLB server BalanceLoad RPC). Exactly +// how this detection is done is context and server dependent. +enum GrpclbRouteType { + // Server didn't detect the route that a client took to reach it. + GRPCLB_ROUTE_TYPE_UNKNOWN = 0; + // Indicates that a client reached a server via gRPCLB fallback. + GRPCLB_ROUTE_TYPE_FALLBACK = 1; + // Indicates that a client reached a server as a gRPCLB-given backend. + GRPCLB_ROUTE_TYPE_BACKEND = 2; +} + +// Unary request. +message SimpleRequest { + // Desired payload type in the response from the server. + // If response_type is RANDOM, server randomly chooses one from other formats. + PayloadType response_type = 1; + + // Desired payload size in the response from the server. + int32 response_size = 2; + + // Optional input payload sent along with the request. + Payload payload = 3; + + // Whether SimpleResponse should include username. + bool fill_username = 4; + + // Whether SimpleResponse should include OAuth scope. + bool fill_oauth_scope = 5; + + // Whether to request the server to compress the response. This field is + // "nullable" in order to interoperate seamlessly with clients not able to + // implement the full compression tests by introspecting the call to verify + // the response's compression status. + BoolValue response_compressed = 6; + + // Whether server should return a given status + EchoStatus response_status = 7; + + // Whether the server should expect this request to be compressed. + BoolValue expect_compressed = 8; + + // Whether SimpleResponse should include server_id. + bool fill_server_id = 9; + + // Whether SimpleResponse should include grpclb_route_type. + bool fill_grpclb_route_type = 10; +} + +// Unary response, as configured by the request. +message SimpleResponse { + // Payload to increase message size. + Payload payload = 1; + // The user the request came from, for verifying authentication was + // successful when the client expected it. + string username = 2; + // OAuth scope. + string oauth_scope = 3; + + // Server ID. This must be unique among different server instances, + // but the same across all RPC's made to a particular server instance. + string server_id = 4; + // gRPCLB Path. + GrpclbRouteType grpclb_route_type = 5; + + // Server hostname. + string hostname = 6; +} + +// Client-streaming request. +message StreamingInputCallRequest { + // Optional input payload sent along with the request. + Payload payload = 1; + + // Whether the server should expect this request to be compressed. This field + // is "nullable" in order to interoperate seamlessly with servers not able to + // implement the full compression tests by introspecting the call to verify + // the request's compression status. + BoolValue expect_compressed = 2; + + // Not expecting any payload from the response. +} + +// Client-streaming response. +message StreamingInputCallResponse { + // Aggregated size of payloads received from the client. + int32 aggregated_payload_size = 1; +} + +// Configuration for a particular response. +message ResponseParameters { + // Desired payload sizes in responses from the server. + int32 size = 1; + + // Desired interval between consecutive responses in the response stream in + // microseconds. + int32 interval_us = 2; + + // Whether to request the server to compress the response. This field is + // "nullable" in order to interoperate seamlessly with clients not able to + // implement the full compression tests by introspecting the call to verify + // the response's compression status. + BoolValue compressed = 3; +} + +// Server-streaming request. +message StreamingOutputCallRequest { + // Desired payload type in the response from the server. + // If response_type is RANDOM, the payload from each response in the stream + // might be of different types. This is to simulate a mixed type of payload + // stream. + PayloadType response_type = 1; + + // Configuration for each expected response message. + repeated ResponseParameters response_parameters = 2; + + // Optional input payload sent along with the request. + Payload payload = 3; + + // Whether server should return a given status + EchoStatus response_status = 7; +} + +// Server-streaming response, as configured by the request and parameters. +message StreamingOutputCallResponse { + // Payload to increase response size. + Payload payload = 1; +} + +// For reconnect interop test only. +// Client tells server what reconnection parameters it used. +message ReconnectParams { + int32 max_reconnect_backoff_ms = 1; +} + +// For reconnect interop test only. +// Server tells client whether its reconnects are following the spec and the +// reconnect backoffs it saw. +message ReconnectInfo { + bool passed = 1; + repeated int32 backoff_ms = 2; +} + +message LoadBalancerStatsRequest { + // Request stats for the next num_rpcs sent by client. + int32 num_rpcs = 1; + // If num_rpcs have not completed within timeout_sec, return partial results. + int32 timeout_sec = 2; +} + +message LoadBalancerStatsResponse { + message RpcsByPeer { + // The number of completed RPCs for each peer. + map rpcs_by_peer = 1; + } + // The number of completed RPCs for each peer. + map rpcs_by_peer = 1; + // The number of RPCs that failed to record a remote peer. + int32 num_failures = 2; + map rpcs_by_method = 3; +} diff --git a/packages/grpc-js-xds/proto/grpc/testing/test.proto b/packages/grpc-js-xds/proto/grpc/testing/test.proto new file mode 100644 index 00000000..9d0fadd9 --- /dev/null +++ b/packages/grpc-js-xds/proto/grpc/testing/test.proto @@ -0,0 +1,92 @@ + +// Copyright 2015-2016 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. + +// An integration test service that covers all the method signature permutations +// of unary/streaming requests/responses. + +syntax = "proto3"; + +import "grpc/testing/empty.proto"; +import "grpc/testing/messages.proto"; + +package grpc.testing; + +// A simple service to test the various types of RPCs and experiment with +// performance with various types of payload. +service TestService { + // One empty request followed by one empty response. + rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); + + // One request followed by one response. + rpc UnaryCall(SimpleRequest) returns (SimpleResponse); + + // One request followed by one response. Response has cache control + // headers set such that a caching HTTP proxy (such as GFE) can + // satisfy subsequent requests. + rpc CacheableUnaryCall(SimpleRequest) returns (SimpleResponse); + + // One request followed by a sequence of responses (streamed download). + // The server returns the payload with client desired type and sizes. + rpc StreamingOutputCall(StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // A sequence of requests followed by one response (streamed upload). + // The server returns the aggregated size of client payload as the result. + rpc StreamingInputCall(stream StreamingInputCallRequest) + returns (StreamingInputCallResponse); + + // A sequence of requests with each request served by the server immediately. + // As one request could lead to multiple responses, this interface + // demonstrates the idea of full duplexing. + rpc FullDuplexCall(stream StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // A sequence of requests followed by a sequence of responses. + // The server buffers all the client requests and then serves them in order. A + // stream of responses are returned to the client when the server starts with + // first request. + rpc HalfDuplexCall(stream StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // The test server will not implement this method. It will be used + // to test the behavior when clients call unimplemented methods. + rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); +} + +// A simple service NOT implemented at servers so clients can test for +// that case. +service UnimplementedService { + // A call that no server should implement + rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); +} + +// A service used to control reconnect server. +service ReconnectService { + rpc Start(grpc.testing.ReconnectParams) returns (grpc.testing.Empty); + rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo); +} + +// A service used to obtain stats for verifying LB behavior. +service LoadBalancerStatsService { + // Gets the backend distribution for RPCs sent by a test client. + rpc GetClientStats(LoadBalancerStatsRequest) + returns (LoadBalancerStatsResponse) {} +} + +// A service to remotely control health status of an xDS test server. +service XdsUpdateHealthService { + rpc SetServing(grpc.testing.Empty) returns (grpc.testing.Empty); + rpc SetNotServing(grpc.testing.Empty) returns (grpc.testing.Empty); +} diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh new file mode 100644 index 00000000..bbfc3056 --- /dev/null +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# Copyright 2020 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. + +cd $(dirname $0)/.. +base=$(pwd) + +# Install NVM +cd ~ +export NVM_DIR=`pwd`/.nvm +curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.4/install.sh | bash + +# Load NVM +. $NVM_DIR/nvm.sh + +nvm install 12 + +set -exu -o pipefail +[[ -f /VERSION ]] && cat /VERSION + +# Make nvm available to the subprocess that the python script spawns +echo "source $NVM_DIR/nvm.sh" > ~/.profile +echo "source $NVM_DIR/nvm.sh" > ~/.shrc +export ENV=~/.shrc + +cd $base/../grpc-js +npm install + +# grpc-js-xds has a dev dependency on "../grpc-js", so it should pull that in automatically +cd $base +git submodule update --init --recursive +npm install + +cd ../../.. + +git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git + +grpc/tools/run_tests/helper_scripts/prep_xds.sh + +GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver \ + GRPC_NODE_VERBOSITY=DEBUG \ + NODE_XDS_INTEROP_VERBOSITY=1 \ + python3 grpc/tools/run_tests/run_xds_tests.py \ + --test_case="backends_restart,change_backend_service,gentle_failover,ping_pong,remove_instance_group,round_robin,secondary_locality_gets_no_requests_on_partial_primary_failure,secondary_locality_gets_requests_on_primary_failure" \ + --project_id=grpc-testing \ + --source_image=projects/grpc-testing/global/images/xds-test-server-2 \ + --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ + --gcp_suffix=$(date '+%s') \ + --verbose \ + --client_cmd="$(which node) grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ + --server=xds:///{server_uri} \ + --stats_port={stats_port} \ + --qps={qps} \ + {fail_on_failed_rpc} \ + {rpcs_to_send} \ + {metadata_to_send}" diff --git a/packages/grpc-js/src/generated/ads.ts b/packages/grpc-js-xds/src/generated/ads.ts similarity index 99% rename from packages/grpc-js/src/generated/ads.ts rename to packages/grpc-js-xds/src/generated/ads.ts index a33270cc..10c420a1 100644 --- a/packages/grpc-js/src/generated/ads.ts +++ b/packages/grpc-js-xds/src/generated/ads.ts @@ -1,4 +1,4 @@ -import * as grpc from '../index'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; import { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v2_AggregatedDiscoveryServiceClient } from './envoy/service/discovery/v2/AggregatedDiscoveryService'; @@ -6,7 +6,7 @@ import { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v2_Aggrega type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { envoy: { diff --git a/packages/grpc-js/src/generated/cluster.ts b/packages/grpc-js-xds/src/generated/cluster.ts similarity index 99% rename from packages/grpc-js/src/generated/cluster.ts rename to packages/grpc-js-xds/src/generated/cluster.ts index 7d2b34a4..b165ae6b 100644 --- a/packages/grpc-js/src/generated/cluster.ts +++ b/packages/grpc-js-xds/src/generated/cluster.ts @@ -1,11 +1,11 @@ -import * as grpc from '../index'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { envoy: { diff --git a/packages/grpc-js/src/generated/endpoint.ts b/packages/grpc-js-xds/src/generated/endpoint.ts similarity index 99% rename from packages/grpc-js/src/generated/endpoint.ts rename to packages/grpc-js-xds/src/generated/endpoint.ts index ade62c99..18c43984 100644 --- a/packages/grpc-js/src/generated/endpoint.ts +++ b/packages/grpc-js-xds/src/generated/endpoint.ts @@ -1,11 +1,11 @@ -import * as grpc from '../index'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { envoy: { diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Cluster.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/Cluster.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/ClusterLoadAssignment.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/ClusterLoadAssignment.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Listener.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/Listener.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/Listener.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/LoadBalancingPolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/LoadBalancingPolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/Resource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/RouteConfiguration.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/RouteConfiguration.ts diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts new file mode 100644 index 00000000..02810bf0 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts @@ -0,0 +1,204 @@ +// Original file: deps/envoy-api/envoy/api/v2/scoped_route.proto + + +export interface _envoy_api_v2_ScopedRouteConfiguration_Key_Fragment { + /** + * A string to match against. + */ + 'string_key'?: (string); + 'type'?: "string_key"; +} + +export interface _envoy_api_v2_ScopedRouteConfiguration_Key_Fragment__Output { + /** + * A string to match against. + */ + 'string_key'?: (string); + 'type': "string_key"; +} + +/** + * Specifies a key which is matched against the output of the + * :ref:`scope_key_builder` + * specified in the HttpConnectionManager. The matching is done per HTTP + * request and is dependent on the order of the fragments contained in the + * Key. + */ +export interface _envoy_api_v2_ScopedRouteConfiguration_Key { + /** + * The ordered set of fragments to match against. The order must match the + * fragments in the corresponding + * :ref:`scope_key_builder`. + */ + 'fragments'?: (_envoy_api_v2_ScopedRouteConfiguration_Key_Fragment)[]; +} + +/** + * Specifies a key which is matched against the output of the + * :ref:`scope_key_builder` + * specified in the HttpConnectionManager. The matching is done per HTTP + * request and is dependent on the order of the fragments contained in the + * Key. + */ +export interface _envoy_api_v2_ScopedRouteConfiguration_Key__Output { + /** + * The ordered set of fragments to match against. The order must match the + * fragments in the corresponding + * :ref:`scope_key_builder`. + */ + 'fragments': (_envoy_api_v2_ScopedRouteConfiguration_Key_Fragment__Output)[]; +} + +/** + * Specifies a routing scope, which associates a + * :ref:`Key` to a + * :ref:`envoy_api_msg_RouteConfiguration` (identified by its resource name). + * + * The HTTP connection manager builds up a table consisting of these Key to + * RouteConfiguration mappings, and looks up the RouteConfiguration to use per + * request according to the algorithm specified in the + * :ref:`scope_key_builder` + * assigned to the HttpConnectionManager. + * + * For example, with the following configurations (in YAML): + * + * HttpConnectionManager config: + * + * .. code:: + * + * ... + * scoped_routes: + * name: foo-scoped-routes + * scope_key_builder: + * fragments: + * - header_value_extractor: + * name: X-Route-Selector + * element_separator: , + * element: + * separator: = + * key: vip + * + * ScopedRouteConfiguration resources (specified statically via + * :ref:`scoped_route_configurations_list` + * or obtained dynamically via SRDS): + * + * .. code:: + * + * (1) + * name: route-scope1 + * route_configuration_name: route-config1 + * key: + * fragments: + * - string_key: 172.10.10.20 + * + * (2) + * name: route-scope2 + * route_configuration_name: route-config2 + * key: + * fragments: + * - string_key: 172.20.20.30 + * + * A request from a client such as: + * + * .. code:: + * + * GET / HTTP/1.1 + * Host: foo.com + * X-Route-Selector: vip=172.10.10.20 + * + * would result in the routing table defined by the `route-config1` + * RouteConfiguration being assigned to the HTTP request/stream. + */ +export interface ScopedRouteConfiguration { + /** + * The name assigned to the routing scope. + */ + 'name'?: (string); + /** + * The resource name to use for a :ref:`envoy_api_msg_DiscoveryRequest` to an + * RDS server to fetch the :ref:`envoy_api_msg_RouteConfiguration` associated + * with this scope. + */ + 'route_configuration_name'?: (string); + /** + * The key to match against. + */ + 'key'?: (_envoy_api_v2_ScopedRouteConfiguration_Key); +} + +/** + * Specifies a routing scope, which associates a + * :ref:`Key` to a + * :ref:`envoy_api_msg_RouteConfiguration` (identified by its resource name). + * + * The HTTP connection manager builds up a table consisting of these Key to + * RouteConfiguration mappings, and looks up the RouteConfiguration to use per + * request according to the algorithm specified in the + * :ref:`scope_key_builder` + * assigned to the HttpConnectionManager. + * + * For example, with the following configurations (in YAML): + * + * HttpConnectionManager config: + * + * .. code:: + * + * ... + * scoped_routes: + * name: foo-scoped-routes + * scope_key_builder: + * fragments: + * - header_value_extractor: + * name: X-Route-Selector + * element_separator: , + * element: + * separator: = + * key: vip + * + * ScopedRouteConfiguration resources (specified statically via + * :ref:`scoped_route_configurations_list` + * or obtained dynamically via SRDS): + * + * .. code:: + * + * (1) + * name: route-scope1 + * route_configuration_name: route-config1 + * key: + * fragments: + * - string_key: 172.10.10.20 + * + * (2) + * name: route-scope2 + * route_configuration_name: route-config2 + * key: + * fragments: + * - string_key: 172.20.20.30 + * + * A request from a client such as: + * + * .. code:: + * + * GET / HTTP/1.1 + * Host: foo.com + * X-Route-Selector: vip=172.10.10.20 + * + * would result in the routing table defined by the `route-config1` + * RouteConfiguration being assigned to the HTTP request/stream. + */ +export interface ScopedRouteConfiguration__Output { + /** + * The name assigned to the routing scope. + */ + 'name': (string); + /** + * The resource name to use for a :ref:`envoy_api_msg_DiscoveryRequest` to an + * RDS server to fetch the :ref:`envoy_api_msg_RouteConfiguration` associated + * with this scope. + */ + 'route_configuration_name': (string); + /** + * The key to match against. + */ + 'key'?: (_envoy_api_v2_ScopedRouteConfiguration_Key__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamBindConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamBindConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Vhds.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/Vhds.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CommonTlsContext.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CommonTlsContext.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/GenericSecret.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/GenericSecret.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/Secret.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/Secret.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsCertificate.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsCertificate.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsParameters.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsParameters.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/Filter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/Filter.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/OutlierDetection.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/OutlierDetection.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Address.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Address.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiConfigSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiConfigSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiVersion.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiVersion.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ConfigSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/ConfigSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ControlPlane.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/ControlPlane.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/DataSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/DataSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/EventServiceConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/EventServiceConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcService.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcService.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderMap.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderMap.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValue.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValue.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthCheck.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthCheck.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthStatus.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthStatus.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Locality.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Locality.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Locality.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Locality.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Pipe.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Pipe.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RateLimitSettings.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RateLimitSettings.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RequestMethod.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RequestMethod.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RoutingPriority.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RoutingPriority.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeDouble.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeDouble.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeUInt32.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeUInt32.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SelfConfigSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/SelfConfigSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketAddress.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketAddress.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketOption.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketOption.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TrafficDirection.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/TrafficDirection.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts new file mode 100644 index 00000000..8b249289 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts @@ -0,0 +1,117 @@ +// Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto + +import { UpstreamLocalityStats as _envoy_api_v2_endpoint_UpstreamLocalityStats, UpstreamLocalityStats__Output as _envoy_api_v2_endpoint_UpstreamLocalityStats__Output } from '../../../../envoy/api/v2/endpoint/UpstreamLocalityStats'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import { Long } from '@grpc/proto-loader'; + +export interface _envoy_api_v2_endpoint_ClusterStats_DroppedRequests { + /** + * Identifier for the policy specifying the drop. + */ + 'category'?: (string); + /** + * Total number of deliberately dropped requests for the category. + */ + 'dropped_count'?: (number | string | Long); +} + +export interface _envoy_api_v2_endpoint_ClusterStats_DroppedRequests__Output { + /** + * Identifier for the policy specifying the drop. + */ + 'category': (string); + /** + * Total number of deliberately dropped requests for the category. + */ + 'dropped_count': (string); +} + +/** + * Per cluster load stats. Envoy reports these stats a management server in a + * :ref:`LoadStatsRequest` + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + * Next ID: 7 + * [#next-free-field: 7] + */ +export interface ClusterStats { + /** + * The name of the cluster. + */ + 'cluster_name'?: (string); + /** + * Need at least one. + */ + 'upstream_locality_stats'?: (_envoy_api_v2_endpoint_UpstreamLocalityStats)[]; + /** + * Cluster-level stats such as total_successful_requests may be computed by + * summing upstream_locality_stats. In addition, below there are additional + * cluster-wide stats. + * + * The total number of dropped requests. This covers requests + * deliberately dropped by the drop_overload policy and circuit breaking. + */ + 'total_dropped_requests'?: (number | string | Long); + /** + * Period over which the actual load report occurred. This will be guaranteed to include every + * request reported. Due to system load and delays between the *LoadStatsRequest* sent from Envoy + * and the *LoadStatsResponse* message sent from the management server, this may be longer than + * the requested load reporting interval in the *LoadStatsResponse*. + */ + 'load_report_interval'?: (_google_protobuf_Duration); + /** + * Information about deliberately dropped requests for each category specified + * in the DropOverload policy. + */ + 'dropped_requests'?: (_envoy_api_v2_endpoint_ClusterStats_DroppedRequests)[]; + /** + * The eds_cluster_config service_name of the cluster. + * It's possible that two clusters send the same service_name to EDS, + * in that case, the management server is supposed to do aggregation on the load reports. + */ + 'cluster_service_name'?: (string); +} + +/** + * Per cluster load stats. Envoy reports these stats a management server in a + * :ref:`LoadStatsRequest` + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + * Next ID: 7 + * [#next-free-field: 7] + */ +export interface ClusterStats__Output { + /** + * The name of the cluster. + */ + 'cluster_name': (string); + /** + * Need at least one. + */ + 'upstream_locality_stats': (_envoy_api_v2_endpoint_UpstreamLocalityStats__Output)[]; + /** + * Cluster-level stats such as total_successful_requests may be computed by + * summing upstream_locality_stats. In addition, below there are additional + * cluster-wide stats. + * + * The total number of dropped requests. This covers requests + * deliberately dropped by the drop_overload policy and circuit breaking. + */ + 'total_dropped_requests': (string); + /** + * Period over which the actual load report occurred. This will be guaranteed to include every + * request reported. Due to system load and delays between the *LoadStatsRequest* sent from Envoy + * and the *LoadStatsResponse* message sent from the management server, this may be longer than + * the requested load reporting interval in the *LoadStatsResponse*. + */ + 'load_report_interval'?: (_google_protobuf_Duration__Output); + /** + * Information about deliberately dropped requests for each category specified + * in the DropOverload policy. + */ + 'dropped_requests': (_envoy_api_v2_endpoint_ClusterStats_DroppedRequests__Output)[]; + /** + * The eds_cluster_config service_name of the cluster. + * It's possible that two clusters send the same service_name to EDS, + * in that case, the management server is supposed to do aggregation on the load reports. + */ + 'cluster_service_name': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/Endpoint.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/Endpoint.ts diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts new file mode 100644 index 00000000..a42087c9 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts @@ -0,0 +1,41 @@ +// Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto + +import { Long } from '@grpc/proto-loader'; + +/** + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + */ +export interface EndpointLoadMetricStats { + /** + * Name of the metric; may be empty. + */ + 'metric_name'?: (string); + /** + * Number of calls that finished and included this metric. + */ + 'num_requests_finished_with_metric'?: (number | string | Long); + /** + * Sum of metric values across all calls that finished with this metric for + * load_reporting_interval. + */ + 'total_metric_value'?: (number | string); +} + +/** + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + */ +export interface EndpointLoadMetricStats__Output { + /** + * Name of the metric; may be empty. + */ + 'metric_name': (string); + /** + * Number of calls that finished and included this metric. + */ + 'num_requests_finished_with_metric': (string); + /** + * Sum of metric values across all calls that finished with this metric for + * load_reporting_interval. + */ + 'total_metric_value': (number | string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts new file mode 100644 index 00000000..4d2df5d2 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts @@ -0,0 +1,106 @@ +// Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto + +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; +import { EndpointLoadMetricStats as _envoy_api_v2_endpoint_EndpointLoadMetricStats, EndpointLoadMetricStats__Output as _envoy_api_v2_endpoint_EndpointLoadMetricStats__Output } from '../../../../envoy/api/v2/endpoint/EndpointLoadMetricStats'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Long } from '@grpc/proto-loader'; + +/** + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + * [#next-free-field: 8] + */ +export interface UpstreamEndpointStats { + /** + * Upstream host address. + */ + 'address'?: (_envoy_api_v2_core_Address); + /** + * The total number of requests successfully completed by the endpoints in the + * locality. These include non-5xx responses for HTTP, where errors + * originate at the client and the endpoint responded successfully. For gRPC, + * the grpc-status values are those not covered by total_error_requests below. + */ + 'total_successful_requests'?: (number | string | Long); + /** + * The total number of unfinished requests for this endpoint. + */ + 'total_requests_in_progress'?: (number | string | Long); + /** + * The total number of requests that failed due to errors at the endpoint. + * For HTTP these are responses with 5xx status codes and for gRPC the + * grpc-status values: + * + * - DeadlineExceeded + * - Unimplemented + * - Internal + * - Unavailable + * - Unknown + * - DataLoss + */ + 'total_error_requests'?: (number | string | Long); + /** + * Stats for multi-dimensional load balancing. + */ + 'load_metric_stats'?: (_envoy_api_v2_endpoint_EndpointLoadMetricStats)[]; + /** + * Opaque and implementation dependent metadata of the + * endpoint. Envoy will pass this directly to the management server. + */ + 'metadata'?: (_google_protobuf_Struct); + /** + * The total number of requests that were issued to this endpoint + * since the last report. A single TCP connection, HTTP or gRPC + * request or stream is counted as one request. + */ + 'total_issued_requests'?: (number | string | Long); +} + +/** + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + * [#next-free-field: 8] + */ +export interface UpstreamEndpointStats__Output { + /** + * Upstream host address. + */ + 'address'?: (_envoy_api_v2_core_Address__Output); + /** + * The total number of requests successfully completed by the endpoints in the + * locality. These include non-5xx responses for HTTP, where errors + * originate at the client and the endpoint responded successfully. For gRPC, + * the grpc-status values are those not covered by total_error_requests below. + */ + 'total_successful_requests': (string); + /** + * The total number of unfinished requests for this endpoint. + */ + 'total_requests_in_progress': (string); + /** + * The total number of requests that failed due to errors at the endpoint. + * For HTTP these are responses with 5xx status codes and for gRPC the + * grpc-status values: + * + * - DeadlineExceeded + * - Unimplemented + * - Internal + * - Unavailable + * - Unknown + * - DataLoss + */ + 'total_error_requests': (string); + /** + * Stats for multi-dimensional load balancing. + */ + 'load_metric_stats': (_envoy_api_v2_endpoint_EndpointLoadMetricStats__Output)[]; + /** + * Opaque and implementation dependent metadata of the + * endpoint. Envoy will pass this directly to the management server. + */ + 'metadata'?: (_google_protobuf_Struct__Output); + /** + * The total number of requests that were issued to this endpoint + * since the last report. A single TCP connection, HTTP or gRPC + * request or stream is counted as one request. + */ + 'total_issued_requests': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts new file mode 100644 index 00000000..946ca76b --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts @@ -0,0 +1,108 @@ +// Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto + +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; +import { EndpointLoadMetricStats as _envoy_api_v2_endpoint_EndpointLoadMetricStats, EndpointLoadMetricStats__Output as _envoy_api_v2_endpoint_EndpointLoadMetricStats__Output } from '../../../../envoy/api/v2/endpoint/EndpointLoadMetricStats'; +import { UpstreamEndpointStats as _envoy_api_v2_endpoint_UpstreamEndpointStats, UpstreamEndpointStats__Output as _envoy_api_v2_endpoint_UpstreamEndpointStats__Output } from '../../../../envoy/api/v2/endpoint/UpstreamEndpointStats'; +import { Long } from '@grpc/proto-loader'; + +/** + * These are stats Envoy reports to GLB every so often. Report frequency is + * defined by + * :ref:`LoadStatsResponse.load_reporting_interval`. + * Stats per upstream region/zone and optionally per subzone. + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + * [#next-free-field: 9] + */ +export interface UpstreamLocalityStats { + /** + * Name of zone, region and optionally endpoint group these metrics were + * collected from. Zone and region names could be empty if unknown. + */ + 'locality'?: (_envoy_api_v2_core_Locality); + /** + * The total number of requests successfully completed by the endpoints in the + * locality. + */ + 'total_successful_requests'?: (number | string | Long); + /** + * The total number of unfinished requests + */ + 'total_requests_in_progress'?: (number | string | Long); + /** + * The total number of requests that failed due to errors at the endpoint, + * aggregated over all endpoints in the locality. + */ + 'total_error_requests'?: (number | string | Long); + /** + * Stats for multi-dimensional load balancing. + */ + 'load_metric_stats'?: (_envoy_api_v2_endpoint_EndpointLoadMetricStats)[]; + /** + * [#not-implemented-hide:] The priority of the endpoint group these metrics + * were collected from. + */ + 'priority'?: (number); + /** + * Endpoint granularity stats information for this locality. This information + * is populated if the Server requests it by setting + * :ref:`LoadStatsResponse.report_endpoint_granularity`. + */ + 'upstream_endpoint_stats'?: (_envoy_api_v2_endpoint_UpstreamEndpointStats)[]; + /** + * The total number of requests that were issued by this Envoy since + * the last report. This information is aggregated over all the + * upstream endpoints in the locality. + */ + 'total_issued_requests'?: (number | string | Long); +} + +/** + * These are stats Envoy reports to GLB every so often. Report frequency is + * defined by + * :ref:`LoadStatsResponse.load_reporting_interval`. + * Stats per upstream region/zone and optionally per subzone. + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + * [#next-free-field: 9] + */ +export interface UpstreamLocalityStats__Output { + /** + * Name of zone, region and optionally endpoint group these metrics were + * collected from. Zone and region names could be empty if unknown. + */ + 'locality'?: (_envoy_api_v2_core_Locality__Output); + /** + * The total number of requests successfully completed by the endpoints in the + * locality. + */ + 'total_successful_requests': (string); + /** + * The total number of unfinished requests + */ + 'total_requests_in_progress': (string); + /** + * The total number of requests that failed due to errors at the endpoint, + * aggregated over all endpoints in the locality. + */ + 'total_error_requests': (string); + /** + * Stats for multi-dimensional load balancing. + */ + 'load_metric_stats': (_envoy_api_v2_endpoint_EndpointLoadMetricStats__Output)[]; + /** + * [#not-implemented-hide:] The priority of the endpoint group these metrics + * were collected from. + */ + 'priority': (number); + /** + * Endpoint granularity stats information for this locality. This information + * is populated if the Server requests it by setting + * :ref:`LoadStatsResponse.report_endpoint_granularity`. + */ + 'upstream_endpoint_stats': (_envoy_api_v2_endpoint_UpstreamEndpointStats__Output)[]; + /** + * The total number of requests that were issued by this Envoy since + * the last report. This information is aggregated over all the + * upstream endpoints in the locality. + */ + 'total_issued_requests': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/Filter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/Filter.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChain.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChain.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChainMatch.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChainMatch.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/CorsPolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/CorsPolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Decorator.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/Decorator.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/DirectResponseAction.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/DirectResponseAction.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/FilterAction.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/FilterAction.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HeaderMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/HeaderMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HedgePolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/HedgePolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RateLimit.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/RateLimit.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RedirectAction.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/RedirectAction.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RetryPolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/RetryPolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Route.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/Route.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteAction.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteAction.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteMatch.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteMatch.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Tracing.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/Tracing.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualCluster.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualCluster.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualHost.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualHost.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/WeightedCluster.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/WeightedCluster.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts new file mode 100644 index 00000000..9aa2b2d2 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts @@ -0,0 +1,1039 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { Rds as _envoy_config_filter_network_http_connection_manager_v2_Rds, Rds__Output as _envoy_config_filter_network_http_connection_manager_v2_Rds__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/Rds'; +import { RouteConfiguration as _envoy_api_v2_RouteConfiguration, RouteConfiguration__Output as _envoy_api_v2_RouteConfiguration__Output } from '../../../../../../envoy/api/v2/RouteConfiguration'; +import { HttpFilter as _envoy_config_filter_network_http_connection_manager_v2_HttpFilter, HttpFilter__Output as _envoy_config_filter_network_http_connection_manager_v2_HttpFilter__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/HttpFilter'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../../../google/protobuf/BoolValue'; +import { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/Http1ProtocolOptions'; +import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/Http2ProtocolOptions'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../../../google/protobuf/Duration'; +import { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from '../../../../../../envoy/config/filter/accesslog/v2/AccessLog'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../../../google/protobuf/UInt32Value'; +import { ScopedRoutes as _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes, ScopedRoutes__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes'; +import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/HttpProtocolOptions'; +import { RequestIDExtension as _envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension, RequestIDExtension__Output as _envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../../../../envoy/type/Percent'; +import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from '../../../../../../envoy/type/tracing/v2/CustomTag'; +import { _envoy_config_trace_v2_Tracing_Http, _envoy_config_trace_v2_Tracing_Http__Output } from '../../../../../../envoy/config/trace/v2/Tracing'; + +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_CodecType { + /** + * For every new connection, the connection manager will determine which + * codec to use. This mode supports both ALPN for TLS listeners as well as + * protocol inference for plaintext listeners. If ALPN data is available, it + * is preferred, otherwise protocol inference is used. In almost all cases, + * this is the right option to choose for this setting. + */ + AUTO = 0, + /** + * The connection manager will assume that the client is speaking HTTP/1.1. + */ + HTTP1 = 1, + /** + * The connection manager will assume that the client is speaking HTTP/2 + * (Envoy does not require HTTP/2 to take place over TLS or to use ALPN. + * Prior knowledge is allowed). + */ + HTTP2 = 2, + /** + * [#not-implemented-hide:] QUIC implementation is not production ready yet. Use this enum with + * caution to prevent accidental execution of QUIC code. I.e. `!= HTTP2` is no longer sufficient + * to distinguish HTTP1 and HTTP2 traffic. + */ + HTTP3 = 3, +} + +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +/** + * How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP + * header. + */ +export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ForwardClientCertDetails { + /** + * Do not send the XFCC header to the next hop. This is the default value. + */ + SANITIZE = 0, + /** + * When the client connection is mTLS (Mutual TLS), forward the XFCC header + * in the request. + */ + FORWARD_ONLY = 1, + /** + * When the client connection is mTLS, append the client certificate + * information to the request’s XFCC header and forward it. + */ + APPEND_FORWARD = 2, + /** + * When the client connection is mTLS, reset the XFCC header with the client + * certificate information and send it to the next hop. + */ + SANITIZE_SET = 3, + /** + * Always forward the XFCC header in the request, regardless of whether the + * client connection is mTLS. + */ + ALWAYS_FORWARD_ONLY = 4, +} + +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_InternalAddressConfig { + /** + * Whether unix socket addresses should be considered internal. + */ + 'unix_sockets'?: (boolean); +} + +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_InternalAddressConfig__Output { + /** + * Whether unix socket addresses should be considered internal. + */ + 'unix_sockets': (boolean); +} + +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing_OperationName { + /** + * The HTTP listener is used for ingress/incoming requests. + */ + INGRESS = 0, + /** + * The HTTP listener is used for egress/outgoing requests. + */ + EGRESS = 1, +} + +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ServerHeaderTransformation { + /** + * Overwrite any Server header with the contents of server_name. + */ + OVERWRITE = 0, + /** + * If no Server header is present, append Server server_name + * If a Server header is present, pass it through. + */ + APPEND_IF_ABSENT = 1, + /** + * Pass through the value of the server header, and do not append a header + * if none is present. + */ + PASS_THROUGH = 2, +} + +/** + * [#next-free-field: 7] + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_SetCurrentClientCertDetails { + /** + * Whether to forward the subject of the client cert. Defaults to false. + */ + 'subject'?: (_google_protobuf_BoolValue); + /** + * Whether to forward the entire client cert in URL encoded PEM format. This will appear in the + * XFCC header comma separated from other values with the value Cert="PEM". + * Defaults to false. + */ + 'cert'?: (boolean); + /** + * Whether to forward the entire client cert chain (including the leaf cert) in URL encoded PEM + * format. This will appear in the XFCC header comma separated from other values with the value + * Chain="PEM". + * Defaults to false. + */ + 'chain'?: (boolean); + /** + * Whether to forward the DNS type Subject Alternative Names of the client cert. + * Defaults to false. + */ + 'dns'?: (boolean); + /** + * Whether to forward the URI type Subject Alternative Name of the client cert. Defaults to + * false. + */ + 'uri'?: (boolean); +} + +/** + * [#next-free-field: 7] + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_SetCurrentClientCertDetails__Output { + /** + * Whether to forward the subject of the client cert. Defaults to false. + */ + 'subject'?: (_google_protobuf_BoolValue__Output); + /** + * Whether to forward the entire client cert in URL encoded PEM format. This will appear in the + * XFCC header comma separated from other values with the value Cert="PEM". + * Defaults to false. + */ + 'cert': (boolean); + /** + * Whether to forward the entire client cert chain (including the leaf cert) in URL encoded PEM + * format. This will appear in the XFCC header comma separated from other values with the value + * Chain="PEM". + * Defaults to false. + */ + 'chain': (boolean); + /** + * Whether to forward the DNS type Subject Alternative Names of the client cert. + * Defaults to false. + */ + 'dns': (boolean); + /** + * Whether to forward the URI type Subject Alternative Name of the client cert. Defaults to + * false. + */ + 'uri': (boolean); +} + +/** + * [#next-free-field: 10] + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing { + /** + * The span name will be derived from this field. If + * :ref:`traffic_direction ` is + * specified on the parent listener, then it is used instead of this field. + * + * .. attention:: + * This field has been deprecated in favor of `traffic_direction`. + */ + 'operation_name'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing_OperationName | keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing_OperationName); + /** + * A list of header names used to create tags for the active span. The header name is used to + * populate the tag name, and the header value is used to populate the tag value. The tag is + * created if the specified header name is present in the request's headers. + * + * .. attention:: + * This field has been deprecated in favor of :ref:`custom_tags + * `. + */ + 'request_headers_for_tags'?: (string)[]; + /** + * Target percentage of requests managed by this HTTP connection manager that will be force + * traced if the :ref:`x-client-trace-id ` + * header is set. This field is a direct analog for the runtime variable + * 'tracing.client_sampling' in the :ref:`HTTP Connection Manager + * `. + * Default: 100% + */ + 'client_sampling'?: (_envoy_type_Percent); + /** + * Target percentage of requests managed by this HTTP connection manager that will be randomly + * selected for trace generation, if not requested by the client or not forced. This field is + * a direct analog for the runtime variable 'tracing.random_sampling' in the + * :ref:`HTTP Connection Manager `. + * Default: 100% + */ + 'random_sampling'?: (_envoy_type_Percent); + /** + * Target percentage of requests managed by this HTTP connection manager that will be traced + * after all other sampling checks have been applied (client-directed, force tracing, random + * sampling). This field functions as an upper limit on the total configured sampling rate. For + * instance, setting client_sampling to 100% but overall_sampling to 1% will result in only 1% + * of client requests with the appropriate headers to be force traced. This field is a direct + * analog for the runtime variable 'tracing.global_enabled' in the + * :ref:`HTTP Connection Manager `. + * Default: 100% + */ + 'overall_sampling'?: (_envoy_type_Percent); + /** + * Whether to annotate spans with additional data. If true, spans will include logs for stream + * events. + */ + 'verbose'?: (boolean); + /** + * Maximum length of the request path to extract and include in the HttpUrl tag. Used to + * truncate lengthy request paths to meet the needs of a tracing backend. + * Default: 256 + */ + 'max_path_tag_length'?: (_google_protobuf_UInt32Value); + /** + * A list of custom tags with unique tag name to create tags for the active span. + */ + 'custom_tags'?: (_envoy_type_tracing_v2_CustomTag)[]; + /** + * Configuration for an external tracing provider. + * If not specified, no tracing will be performed. + * + * .. attention:: + * Please be aware that *envoy.tracers.opencensus* provider can only be configured once + * in Envoy lifetime. + * Any attempts to reconfigure it or to use different configurations for different HCM filters + * will be rejected. + * Such a constraint is inherent to OpenCensus itself. It cannot be overcome without changes + * on OpenCensus side. + */ + 'provider'?: (_envoy_config_trace_v2_Tracing_Http); +} + +/** + * [#next-free-field: 10] + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing__Output { + /** + * The span name will be derived from this field. If + * :ref:`traffic_direction ` is + * specified on the parent listener, then it is used instead of this field. + * + * .. attention:: + * This field has been deprecated in favor of `traffic_direction`. + */ + 'operation_name': (keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing_OperationName); + /** + * A list of header names used to create tags for the active span. The header name is used to + * populate the tag name, and the header value is used to populate the tag value. The tag is + * created if the specified header name is present in the request's headers. + * + * .. attention:: + * This field has been deprecated in favor of :ref:`custom_tags + * `. + */ + 'request_headers_for_tags': (string)[]; + /** + * Target percentage of requests managed by this HTTP connection manager that will be force + * traced if the :ref:`x-client-trace-id ` + * header is set. This field is a direct analog for the runtime variable + * 'tracing.client_sampling' in the :ref:`HTTP Connection Manager + * `. + * Default: 100% + */ + 'client_sampling'?: (_envoy_type_Percent__Output); + /** + * Target percentage of requests managed by this HTTP connection manager that will be randomly + * selected for trace generation, if not requested by the client or not forced. This field is + * a direct analog for the runtime variable 'tracing.random_sampling' in the + * :ref:`HTTP Connection Manager `. + * Default: 100% + */ + 'random_sampling'?: (_envoy_type_Percent__Output); + /** + * Target percentage of requests managed by this HTTP connection manager that will be traced + * after all other sampling checks have been applied (client-directed, force tracing, random + * sampling). This field functions as an upper limit on the total configured sampling rate. For + * instance, setting client_sampling to 100% but overall_sampling to 1% will result in only 1% + * of client requests with the appropriate headers to be force traced. This field is a direct + * analog for the runtime variable 'tracing.global_enabled' in the + * :ref:`HTTP Connection Manager `. + * Default: 100% + */ + 'overall_sampling'?: (_envoy_type_Percent__Output); + /** + * Whether to annotate spans with additional data. If true, spans will include logs for stream + * events. + */ + 'verbose': (boolean); + /** + * Maximum length of the request path to extract and include in the HttpUrl tag. Used to + * truncate lengthy request paths to meet the needs of a tracing backend. + * Default: 256 + */ + 'max_path_tag_length'?: (_google_protobuf_UInt32Value__Output); + /** + * A list of custom tags with unique tag name to create tags for the active span. + */ + 'custom_tags': (_envoy_type_tracing_v2_CustomTag__Output)[]; + /** + * Configuration for an external tracing provider. + * If not specified, no tracing will be performed. + * + * .. attention:: + * Please be aware that *envoy.tracers.opencensus* provider can only be configured once + * in Envoy lifetime. + * Any attempts to reconfigure it or to use different configurations for different HCM filters + * will be rejected. + * Such a constraint is inherent to OpenCensus itself. It cannot be overcome without changes + * on OpenCensus side. + */ + 'provider'?: (_envoy_config_trace_v2_Tracing_Http__Output); +} + +/** + * The configuration for HTTP upgrades. + * For each upgrade type desired, an UpgradeConfig must be added. + * + * .. warning:: + * + * The current implementation of upgrade headers does not handle + * multi-valued upgrade headers. Support for multi-valued headers may be + * added in the future if needed. + * + * .. warning:: + * The current implementation of upgrade headers does not work with HTTP/2 + * upstreams. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_UpgradeConfig { + /** + * The case-insensitive name of this upgrade, e.g. "websocket". + * For each upgrade type present in upgrade_configs, requests with + * Upgrade: [upgrade_type] + * will be proxied upstream. + */ + 'upgrade_type'?: (string); + /** + * If present, this represents the filter chain which will be created for + * this type of upgrade. If no filters are present, the filter chain for + * HTTP connections will be used for this upgrade type. + */ + 'filters'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpFilter)[]; + /** + * Determines if upgrades are enabled or disabled by default. Defaults to true. + * This can be overridden on a per-route basis with :ref:`cluster + * ` as documented in the + * :ref:`upgrade documentation `. + */ + 'enabled'?: (_google_protobuf_BoolValue); +} + +/** + * The configuration for HTTP upgrades. + * For each upgrade type desired, an UpgradeConfig must be added. + * + * .. warning:: + * + * The current implementation of upgrade headers does not handle + * multi-valued upgrade headers. Support for multi-valued headers may be + * added in the future if needed. + * + * .. warning:: + * The current implementation of upgrade headers does not work with HTTP/2 + * upstreams. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_UpgradeConfig__Output { + /** + * The case-insensitive name of this upgrade, e.g. "websocket". + * For each upgrade type present in upgrade_configs, requests with + * Upgrade: [upgrade_type] + * will be proxied upstream. + */ + 'upgrade_type': (string); + /** + * If present, this represents the filter chain which will be created for + * this type of upgrade. If no filters are present, the filter chain for + * HTTP connections will be used for this upgrade type. + */ + 'filters': (_envoy_config_filter_network_http_connection_manager_v2_HttpFilter__Output)[]; + /** + * Determines if upgrades are enabled or disabled by default. Defaults to true. + * This can be overridden on a per-route basis with :ref:`cluster + * ` as documented in the + * :ref:`upgrade documentation `. + */ + 'enabled'?: (_google_protobuf_BoolValue__Output); +} + +/** + * [#next-free-field: 37] + */ +export interface HttpConnectionManager { + /** + * Supplies the type of codec that the connection manager should use. + */ + 'codec_type'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_CodecType | keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_CodecType); + /** + * The human readable prefix to use when emitting statistics for the + * connection manager. See the :ref:`statistics documentation ` for + * more information. + */ + 'stat_prefix'?: (string); + /** + * The connection manager’s route table will be dynamically loaded via the RDS API. + */ + 'rds'?: (_envoy_config_filter_network_http_connection_manager_v2_Rds); + /** + * The route table for the connection manager is static and is specified in this property. + */ + 'route_config'?: (_envoy_api_v2_RouteConfiguration); + /** + * A list of individual HTTP filters that make up the filter chain for + * requests made to the connection manager. :ref:`Order matters ` + * as the filters are processed sequentially as request events happen. + */ + 'http_filters'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpFilter)[]; + /** + * Whether the connection manager manipulates the :ref:`config_http_conn_man_headers_user-agent` + * and :ref:`config_http_conn_man_headers_downstream-service-cluster` headers. See the linked + * documentation for more information. Defaults to false. + */ + 'add_user_agent'?: (_google_protobuf_BoolValue); + /** + * Presence of the object defines whether the connection manager + * emits :ref:`tracing ` data to the :ref:`configured tracing provider + * `. + */ + 'tracing'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing); + /** + * Additional HTTP/1 settings that are passed to the HTTP/1 codec. + */ + 'http_protocol_options'?: (_envoy_api_v2_core_Http1ProtocolOptions); + /** + * Additional HTTP/2 settings that are passed directly to the HTTP/2 codec. + */ + 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions); + /** + * An optional override that the connection manager will write to the server + * header in responses. If not set, the default is *envoy*. + */ + 'server_name'?: (string); + /** + * The idle timeout for connections managed by the connection manager. The + * idle timeout is defined as the period in which there are no active + * requests. If not set, there is no idle timeout. When the idle timeout is + * reached the connection will be closed. If the connection is an HTTP/2 + * connection a drain sequence will occur prior to closing the connection. + * This field is deprecated. Use :ref:`idle_timeout + * ` + * instead. + */ + 'idle_timeout'?: (_google_protobuf_Duration); + /** + * The time that Envoy will wait between sending an HTTP/2 “shutdown + * notification” (GOAWAY frame with max stream ID) and a final GOAWAY frame. + * This is used so that Envoy provides a grace period for new streams that + * race with the final GOAWAY frame. During this grace period, Envoy will + * continue to accept new streams. After the grace period, a final GOAWAY + * frame is sent and Envoy will start refusing new streams. Draining occurs + * both when a connection hits the idle timeout or during general server + * draining. The default grace period is 5000 milliseconds (5 seconds) if this + * option is not specified. + */ + 'drain_timeout'?: (_google_protobuf_Duration); + /** + * Configuration for :ref:`HTTP access logs ` + * emitted by the connection manager. + */ + 'access_log'?: (_envoy_config_filter_accesslog_v2_AccessLog)[]; + /** + * If set to true, the connection manager will use the real remote address + * of the client connection when determining internal versus external origin and manipulating + * various headers. If set to false or absent, the connection manager will use the + * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. See the documentation for + * :ref:`config_http_conn_man_headers_x-forwarded-for`, + * :ref:`config_http_conn_man_headers_x-envoy-internal`, and + * :ref:`config_http_conn_man_headers_x-envoy-external-address` for more information. + */ + 'use_remote_address'?: (_google_protobuf_BoolValue); + /** + * Whether the connection manager will generate the :ref:`x-request-id + * ` header if it does not exist. This defaults to + * true. Generating a random UUID4 is expensive so in high throughput scenarios where this feature + * is not desired it can be disabled. + */ + 'generate_request_id'?: (_google_protobuf_BoolValue); + /** + * How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP + * header. + */ + 'forward_client_cert_details'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ForwardClientCertDetails | keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ForwardClientCertDetails); + /** + * This field is valid only when :ref:`forward_client_cert_details + * ` + * is APPEND_FORWARD or SANITIZE_SET and the client connection is mTLS. It specifies the fields in + * the client certificate to be forwarded. Note that in the + * :ref:`config_http_conn_man_headers_x-forwarded-client-cert` header, *Hash* is always set, and + * *By* is always set when the client certificate presents the URI type Subject Alternative Name + * value. + */ + 'set_current_client_cert_details'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_SetCurrentClientCertDetails); + /** + * If proxy_100_continue is true, Envoy will proxy incoming "Expect: + * 100-continue" headers upstream, and forward "100 Continue" responses + * downstream. If this is false or not set, Envoy will instead strip the + * "Expect: 100-continue" header, and send a "100 Continue" response itself. + */ + 'proxy_100_continue'?: (boolean); + /** + * The number of additional ingress proxy hops from the right side of the + * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header to trust when + * determining the origin client's IP address. The default is zero if this option + * is not specified. See the documentation for + * :ref:`config_http_conn_man_headers_x-forwarded-for` for more information. + */ + 'xff_num_trusted_hops'?: (number); + /** + * If + * :ref:`use_remote_address + * ` + * is true and represent_ipv4_remote_address_as_ipv4_mapped_ipv6 is true and the remote address is + * an IPv4 address, the address will be mapped to IPv6 before it is appended to *x-forwarded-for*. + * This is useful for testing compatibility of upstream services that parse the header value. For + * example, 50.0.0.1 is represented as ::FFFF:50.0.0.1. See `IPv4-Mapped IPv6 Addresses + * `_ for details. This will also affect the + * :ref:`config_http_conn_man_headers_x-envoy-external-address` header. See + * :ref:`http_connection_manager.represent_ipv4_remote_address_as_ipv4_mapped_ipv6 + * ` for runtime + * control. + * [#not-implemented-hide:] + */ + 'represent_ipv4_remote_address_as_ipv4_mapped_ipv6'?: (boolean); + /** + * If set, Envoy will not append the remote address to the + * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. This may be used in + * conjunction with HTTP filters that explicitly manipulate XFF after the HTTP connection manager + * has mutated the request headers. While :ref:`use_remote_address + * ` + * will also suppress XFF addition, it has consequences for logging and other + * Envoy uses of the remote address, so *skip_xff_append* should be used + * when only an elision of XFF addition is intended. + */ + 'skip_xff_append'?: (boolean); + /** + * Via header value to append to request and response headers. If this is + * empty, no via header will be appended. + */ + 'via'?: (string); + 'upgrade_configs'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_UpgradeConfig)[]; + /** + * The stream idle timeout for connections managed by the connection manager. + * If not specified, this defaults to 5 minutes. The default value was selected + * so as not to interfere with any smaller configured timeouts that may have + * existed in configurations prior to the introduction of this feature, while + * introducing robustness to TCP connections that terminate without a FIN. + * + * This idle timeout applies to new streams and is overridable by the + * :ref:`route-level idle_timeout + * `. Even on a stream in + * which the override applies, prior to receipt of the initial request + * headers, the :ref:`stream_idle_timeout + * ` + * applies. Each time an encode/decode event for headers or data is processed + * for the stream, the timer will be reset. If the timeout fires, the stream + * is terminated with a 408 Request Timeout error code if no upstream response + * header has been received, otherwise a stream reset occurs. + * + * Note that it is possible to idle timeout even if the wire traffic for a stream is non-idle, due + * to the granularity of events presented to the connection manager. For example, while receiving + * very large request headers, it may be the case that there is traffic regularly arriving on the + * wire while the connection manage is only able to observe the end-of-headers event, hence the + * stream may still idle timeout. + * + * A value of 0 will completely disable the connection manager stream idle + * timeout, although per-route idle timeout overrides will continue to apply. + */ + 'stream_idle_timeout'?: (_google_protobuf_Duration); + /** + * Configures what network addresses are considered internal for stats and header sanitation + * purposes. If unspecified, only RFC1918 IP addresses will be considered internal. + * See the documentation for :ref:`config_http_conn_man_headers_x-envoy-internal` for more + * information about internal/external addresses. + */ + 'internal_address_config'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_InternalAddressConfig); + /** + * The delayed close timeout is for downstream connections managed by the HTTP connection manager. + * It is defined as a grace period after connection close processing has been locally initiated + * during which Envoy will wait for the peer to close (i.e., a TCP FIN/RST is received by Envoy + * from the downstream connection) prior to Envoy closing the socket associated with that + * connection. + * NOTE: This timeout is enforced even when the socket associated with the downstream connection + * is pending a flush of the write buffer. However, any progress made writing data to the socket + * will restart the timer associated with this timeout. This means that the total grace period for + * a socket in this state will be + * +. + * + * Delaying Envoy's connection close and giving the peer the opportunity to initiate the close + * sequence mitigates a race condition that exists when downstream clients do not drain/process + * data in a connection's receive buffer after a remote close has been detected via a socket + * write(). This race leads to such clients failing to process the response code sent by Envoy, + * which could result in erroneous downstream processing. + * + * If the timeout triggers, Envoy will close the connection's socket. + * + * The default timeout is 1000 ms if this option is not specified. + * + * .. NOTE:: + * To be useful in avoiding the race condition described above, this timeout must be set + * to *at least* +<100ms to account for + * a reasonable "worst" case processing time for a full iteration of Envoy's event loop>. + * + * .. WARNING:: + * A value of 0 will completely disable delayed close processing. When disabled, the downstream + * connection's socket will be closed immediately after the write flush is completed or will + * never close if the write flush does not complete. + */ + 'delayed_close_timeout'?: (_google_protobuf_Duration); + /** + * The amount of time that Envoy will wait for the entire request to be received. + * The timer is activated when the request is initiated, and is disarmed when the last byte of the + * request is sent upstream (i.e. all decoding filters have processed the request), OR when the + * response is initiated. If not specified or set to 0, this timeout is disabled. + */ + 'request_timeout'?: (_google_protobuf_Duration); + /** + * The maximum request headers size for incoming connections. + * If unconfigured, the default max request headers allowed is 60 KiB. + * Requests that exceed this limit will receive a 431 response. + * The max configurable limit is 96 KiB, based on current implementation + * constraints. + */ + 'max_request_headers_kb'?: (_google_protobuf_UInt32Value); + /** + * Should paths be normalized according to RFC 3986 before any processing of + * requests by HTTP filters or routing? This affects the upstream *:path* header + * as well. For paths that fail this check, Envoy will respond with 400 to + * paths that are malformed. This defaults to false currently but will default + * true in the future. When not specified, this value may be overridden by the + * runtime variable + * :ref:`http_connection_manager.normalize_path`. + * See `Normalization and Comparison ` + * for details of normalization. + * Note that Envoy does not perform + * `case normalization ` + */ + 'normalize_path'?: (_google_protobuf_BoolValue); + /** + * A route table will be dynamically assigned to each request based on request attributes + * (e.g., the value of a header). The "routing scopes" (i.e., route tables) and "scope keys" are + * specified in this message. + */ + 'scoped_routes'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes); + /** + * Whether the connection manager will keep the :ref:`x-request-id + * ` header if passed for a request that is edge + * (Edge request is the request from external clients to front Envoy) and not reset it, which + * is the current Envoy behaviour. This defaults to false. + */ + 'preserve_external_request_id'?: (boolean); + /** + * Determines if adjacent slashes in the path are merged into one before any processing of + * requests by HTTP filters or routing. This affects the upstream *:path* header as well. Without + * setting this option, incoming requests with path `//dir///file` will not match against route + * with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of + * `HTTP spec ` and is provided for convenience. + */ + 'merge_slashes'?: (boolean); + /** + * Defines the action to be applied to the Server header on the response path. + * By default, Envoy will overwrite the header with the value specified in + * server_name. + */ + 'server_header_transformation'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ServerHeaderTransformation | keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ServerHeaderTransformation); + /** + * Additional settings for HTTP requests handled by the connection manager. These will be + * applicable to both HTTP1 and HTTP2 requests. + */ + 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions); + /** + * The configuration of the request ID extension. This includes operations such as + * generation, validation, and associated tracing operations. + * + * If not set, Envoy uses the default UUID-based behavior: + * + * 1. Request ID is propagated using *x-request-id* header. + * + * 2. Request ID is a universally unique identifier (UUID). + * + * 3. Tracing decision (sampled, forced, etc) is set in 14th byte of the UUID. + */ + 'request_id_extension'?: (_envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension); + 'route_specifier'?: "rds"|"route_config"|"scoped_routes"; +} + +/** + * [#next-free-field: 37] + */ +export interface HttpConnectionManager__Output { + /** + * Supplies the type of codec that the connection manager should use. + */ + 'codec_type': (keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_CodecType); + /** + * The human readable prefix to use when emitting statistics for the + * connection manager. See the :ref:`statistics documentation ` for + * more information. + */ + 'stat_prefix': (string); + /** + * The connection manager’s route table will be dynamically loaded via the RDS API. + */ + 'rds'?: (_envoy_config_filter_network_http_connection_manager_v2_Rds__Output); + /** + * The route table for the connection manager is static and is specified in this property. + */ + 'route_config'?: (_envoy_api_v2_RouteConfiguration__Output); + /** + * A list of individual HTTP filters that make up the filter chain for + * requests made to the connection manager. :ref:`Order matters ` + * as the filters are processed sequentially as request events happen. + */ + 'http_filters': (_envoy_config_filter_network_http_connection_manager_v2_HttpFilter__Output)[]; + /** + * Whether the connection manager manipulates the :ref:`config_http_conn_man_headers_user-agent` + * and :ref:`config_http_conn_man_headers_downstream-service-cluster` headers. See the linked + * documentation for more information. Defaults to false. + */ + 'add_user_agent'?: (_google_protobuf_BoolValue__Output); + /** + * Presence of the object defines whether the connection manager + * emits :ref:`tracing ` data to the :ref:`configured tracing provider + * `. + */ + 'tracing'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing__Output); + /** + * Additional HTTP/1 settings that are passed to the HTTP/1 codec. + */ + 'http_protocol_options'?: (_envoy_api_v2_core_Http1ProtocolOptions__Output); + /** + * Additional HTTP/2 settings that are passed directly to the HTTP/2 codec. + */ + 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions__Output); + /** + * An optional override that the connection manager will write to the server + * header in responses. If not set, the default is *envoy*. + */ + 'server_name': (string); + /** + * The idle timeout for connections managed by the connection manager. The + * idle timeout is defined as the period in which there are no active + * requests. If not set, there is no idle timeout. When the idle timeout is + * reached the connection will be closed. If the connection is an HTTP/2 + * connection a drain sequence will occur prior to closing the connection. + * This field is deprecated. Use :ref:`idle_timeout + * ` + * instead. + */ + 'idle_timeout'?: (_google_protobuf_Duration__Output); + /** + * The time that Envoy will wait between sending an HTTP/2 “shutdown + * notification” (GOAWAY frame with max stream ID) and a final GOAWAY frame. + * This is used so that Envoy provides a grace period for new streams that + * race with the final GOAWAY frame. During this grace period, Envoy will + * continue to accept new streams. After the grace period, a final GOAWAY + * frame is sent and Envoy will start refusing new streams. Draining occurs + * both when a connection hits the idle timeout or during general server + * draining. The default grace period is 5000 milliseconds (5 seconds) if this + * option is not specified. + */ + 'drain_timeout'?: (_google_protobuf_Duration__Output); + /** + * Configuration for :ref:`HTTP access logs ` + * emitted by the connection manager. + */ + 'access_log': (_envoy_config_filter_accesslog_v2_AccessLog__Output)[]; + /** + * If set to true, the connection manager will use the real remote address + * of the client connection when determining internal versus external origin and manipulating + * various headers. If set to false or absent, the connection manager will use the + * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. See the documentation for + * :ref:`config_http_conn_man_headers_x-forwarded-for`, + * :ref:`config_http_conn_man_headers_x-envoy-internal`, and + * :ref:`config_http_conn_man_headers_x-envoy-external-address` for more information. + */ + 'use_remote_address'?: (_google_protobuf_BoolValue__Output); + /** + * Whether the connection manager will generate the :ref:`x-request-id + * ` header if it does not exist. This defaults to + * true. Generating a random UUID4 is expensive so in high throughput scenarios where this feature + * is not desired it can be disabled. + */ + 'generate_request_id'?: (_google_protobuf_BoolValue__Output); + /** + * How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP + * header. + */ + 'forward_client_cert_details': (keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ForwardClientCertDetails); + /** + * This field is valid only when :ref:`forward_client_cert_details + * ` + * is APPEND_FORWARD or SANITIZE_SET and the client connection is mTLS. It specifies the fields in + * the client certificate to be forwarded. Note that in the + * :ref:`config_http_conn_man_headers_x-forwarded-client-cert` header, *Hash* is always set, and + * *By* is always set when the client certificate presents the URI type Subject Alternative Name + * value. + */ + 'set_current_client_cert_details'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_SetCurrentClientCertDetails__Output); + /** + * If proxy_100_continue is true, Envoy will proxy incoming "Expect: + * 100-continue" headers upstream, and forward "100 Continue" responses + * downstream. If this is false or not set, Envoy will instead strip the + * "Expect: 100-continue" header, and send a "100 Continue" response itself. + */ + 'proxy_100_continue': (boolean); + /** + * The number of additional ingress proxy hops from the right side of the + * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header to trust when + * determining the origin client's IP address. The default is zero if this option + * is not specified. See the documentation for + * :ref:`config_http_conn_man_headers_x-forwarded-for` for more information. + */ + 'xff_num_trusted_hops': (number); + /** + * If + * :ref:`use_remote_address + * ` + * is true and represent_ipv4_remote_address_as_ipv4_mapped_ipv6 is true and the remote address is + * an IPv4 address, the address will be mapped to IPv6 before it is appended to *x-forwarded-for*. + * This is useful for testing compatibility of upstream services that parse the header value. For + * example, 50.0.0.1 is represented as ::FFFF:50.0.0.1. See `IPv4-Mapped IPv6 Addresses + * `_ for details. This will also affect the + * :ref:`config_http_conn_man_headers_x-envoy-external-address` header. See + * :ref:`http_connection_manager.represent_ipv4_remote_address_as_ipv4_mapped_ipv6 + * ` for runtime + * control. + * [#not-implemented-hide:] + */ + 'represent_ipv4_remote_address_as_ipv4_mapped_ipv6': (boolean); + /** + * If set, Envoy will not append the remote address to the + * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. This may be used in + * conjunction with HTTP filters that explicitly manipulate XFF after the HTTP connection manager + * has mutated the request headers. While :ref:`use_remote_address + * ` + * will also suppress XFF addition, it has consequences for logging and other + * Envoy uses of the remote address, so *skip_xff_append* should be used + * when only an elision of XFF addition is intended. + */ + 'skip_xff_append': (boolean); + /** + * Via header value to append to request and response headers. If this is + * empty, no via header will be appended. + */ + 'via': (string); + 'upgrade_configs': (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_UpgradeConfig__Output)[]; + /** + * The stream idle timeout for connections managed by the connection manager. + * If not specified, this defaults to 5 minutes. The default value was selected + * so as not to interfere with any smaller configured timeouts that may have + * existed in configurations prior to the introduction of this feature, while + * introducing robustness to TCP connections that terminate without a FIN. + * + * This idle timeout applies to new streams and is overridable by the + * :ref:`route-level idle_timeout + * `. Even on a stream in + * which the override applies, prior to receipt of the initial request + * headers, the :ref:`stream_idle_timeout + * ` + * applies. Each time an encode/decode event for headers or data is processed + * for the stream, the timer will be reset. If the timeout fires, the stream + * is terminated with a 408 Request Timeout error code if no upstream response + * header has been received, otherwise a stream reset occurs. + * + * Note that it is possible to idle timeout even if the wire traffic for a stream is non-idle, due + * to the granularity of events presented to the connection manager. For example, while receiving + * very large request headers, it may be the case that there is traffic regularly arriving on the + * wire while the connection manage is only able to observe the end-of-headers event, hence the + * stream may still idle timeout. + * + * A value of 0 will completely disable the connection manager stream idle + * timeout, although per-route idle timeout overrides will continue to apply. + */ + 'stream_idle_timeout'?: (_google_protobuf_Duration__Output); + /** + * Configures what network addresses are considered internal for stats and header sanitation + * purposes. If unspecified, only RFC1918 IP addresses will be considered internal. + * See the documentation for :ref:`config_http_conn_man_headers_x-envoy-internal` for more + * information about internal/external addresses. + */ + 'internal_address_config'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_InternalAddressConfig__Output); + /** + * The delayed close timeout is for downstream connections managed by the HTTP connection manager. + * It is defined as a grace period after connection close processing has been locally initiated + * during which Envoy will wait for the peer to close (i.e., a TCP FIN/RST is received by Envoy + * from the downstream connection) prior to Envoy closing the socket associated with that + * connection. + * NOTE: This timeout is enforced even when the socket associated with the downstream connection + * is pending a flush of the write buffer. However, any progress made writing data to the socket + * will restart the timer associated with this timeout. This means that the total grace period for + * a socket in this state will be + * +. + * + * Delaying Envoy's connection close and giving the peer the opportunity to initiate the close + * sequence mitigates a race condition that exists when downstream clients do not drain/process + * data in a connection's receive buffer after a remote close has been detected via a socket + * write(). This race leads to such clients failing to process the response code sent by Envoy, + * which could result in erroneous downstream processing. + * + * If the timeout triggers, Envoy will close the connection's socket. + * + * The default timeout is 1000 ms if this option is not specified. + * + * .. NOTE:: + * To be useful in avoiding the race condition described above, this timeout must be set + * to *at least* +<100ms to account for + * a reasonable "worst" case processing time for a full iteration of Envoy's event loop>. + * + * .. WARNING:: + * A value of 0 will completely disable delayed close processing. When disabled, the downstream + * connection's socket will be closed immediately after the write flush is completed or will + * never close if the write flush does not complete. + */ + 'delayed_close_timeout'?: (_google_protobuf_Duration__Output); + /** + * The amount of time that Envoy will wait for the entire request to be received. + * The timer is activated when the request is initiated, and is disarmed when the last byte of the + * request is sent upstream (i.e. all decoding filters have processed the request), OR when the + * response is initiated. If not specified or set to 0, this timeout is disabled. + */ + 'request_timeout'?: (_google_protobuf_Duration__Output); + /** + * The maximum request headers size for incoming connections. + * If unconfigured, the default max request headers allowed is 60 KiB. + * Requests that exceed this limit will receive a 431 response. + * The max configurable limit is 96 KiB, based on current implementation + * constraints. + */ + 'max_request_headers_kb'?: (_google_protobuf_UInt32Value__Output); + /** + * Should paths be normalized according to RFC 3986 before any processing of + * requests by HTTP filters or routing? This affects the upstream *:path* header + * as well. For paths that fail this check, Envoy will respond with 400 to + * paths that are malformed. This defaults to false currently but will default + * true in the future. When not specified, this value may be overridden by the + * runtime variable + * :ref:`http_connection_manager.normalize_path`. + * See `Normalization and Comparison ` + * for details of normalization. + * Note that Envoy does not perform + * `case normalization ` + */ + 'normalize_path'?: (_google_protobuf_BoolValue__Output); + /** + * A route table will be dynamically assigned to each request based on request attributes + * (e.g., the value of a header). The "routing scopes" (i.e., route tables) and "scope keys" are + * specified in this message. + */ + 'scoped_routes'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes__Output); + /** + * Whether the connection manager will keep the :ref:`x-request-id + * ` header if passed for a request that is edge + * (Edge request is the request from external clients to front Envoy) and not reset it, which + * is the current Envoy behaviour. This defaults to false. + */ + 'preserve_external_request_id': (boolean); + /** + * Determines if adjacent slashes in the path are merged into one before any processing of + * requests by HTTP filters or routing. This affects the upstream *:path* header as well. Without + * setting this option, incoming requests with path `//dir///file` will not match against route + * with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of + * `HTTP spec ` and is provided for convenience. + */ + 'merge_slashes': (boolean); + /** + * Defines the action to be applied to the Server header on the response path. + * By default, Envoy will overwrite the header with the value specified in + * server_name. + */ + 'server_header_transformation': (keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ServerHeaderTransformation); + /** + * Additional settings for HTTP requests handled by the connection manager. These will be + * applicable to both HTTP1 and HTTP2 requests. + */ + 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions__Output); + /** + * The configuration of the request ID extension. This includes operations such as + * generation, validation, and associated tracing operations. + * + * If not set, Envoy uses the default UUID-based behavior: + * + * 1. Request ID is propagated using *x-request-id* header. + * + * 2. Request ID is a universally unique identifier (UUID). + * + * 3. Tracing decision (sampled, forced, etc) is set in 14th byte of the UUID. + */ + 'request_id_extension'?: (_envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension__Output); + 'route_specifier': "rds"|"route_config"|"scoped_routes"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts new file mode 100644 index 00000000..cf68dd98 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts @@ -0,0 +1,34 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../../google/protobuf/Any'; + +export interface HttpFilter { + /** + * The name of the filter to instantiate. The name must match a + * :ref:`supported filter `. + */ + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + /** + * Filter specific configuration which depends on the filter being instantiated. See the supported + * filters for further documentation. + */ + 'config_type'?: "config"|"typed_config"; +} + +export interface HttpFilter__Output { + /** + * The name of the filter to instantiate. The name must match a + * :ref:`supported filter `. + */ + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Filter specific configuration which depends on the filter being instantiated. See the supported + * filters for further documentation. + */ + 'config_type': "config"|"typed_config"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts new file mode 100644 index 00000000..306cc0dd --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts @@ -0,0 +1,31 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; + +export interface Rds { + /** + * Configuration source specifier for RDS. + */ + 'config_source'?: (_envoy_api_v2_core_ConfigSource); + /** + * The name of the route configuration. This name will be passed to the RDS + * API. This allows an Envoy configuration with multiple HTTP listeners (and + * associated HTTP connection manager filters) to use different route + * configurations. + */ + 'route_config_name'?: (string); +} + +export interface Rds__Output { + /** + * Configuration source specifier for RDS. + */ + 'config_source'?: (_envoy_api_v2_core_ConfigSource__Output); + /** + * The name of the route configuration. This name will be passed to the RDS + * API. This allows an Envoy configuration with multiple HTTP listeners (and + * associated HTTP connection manager filters) to use different route + * configurations. + */ + 'route_config_name': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts new file mode 100644 index 00000000..4688b09c --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../../google/protobuf/Any'; + +export interface RequestIDExtension { + /** + * Request ID extension specific configuration. + */ + 'typed_config'?: (_google_protobuf_Any); +} + +export interface RequestIDExtension__Output { + /** + * Request ID extension specific configuration. + */ + 'typed_config'?: (_google_protobuf_Any__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts new file mode 100644 index 00000000..989aee15 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; + +export interface ScopedRds { + /** + * Configuration source specifier for scoped RDS. + */ + 'scoped_rds_config_source'?: (_envoy_api_v2_core_ConfigSource); +} + +export interface ScopedRds__Output { + /** + * Configuration source specifier for scoped RDS. + */ + 'scoped_rds_config_source'?: (_envoy_api_v2_core_ConfigSource__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts new file mode 100644 index 00000000..81de7333 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { ScopedRouteConfiguration as _envoy_api_v2_ScopedRouteConfiguration, ScopedRouteConfiguration__Output as _envoy_api_v2_ScopedRouteConfiguration__Output } from '../../../../../../envoy/api/v2/ScopedRouteConfiguration'; + +/** + * This message is used to work around the limitations with 'oneof' and repeated fields. + */ +export interface ScopedRouteConfigurationsList { + 'scoped_route_configurations'?: (_envoy_api_v2_ScopedRouteConfiguration)[]; +} + +/** + * This message is used to work around the limitations with 'oneof' and repeated fields. + */ +export interface ScopedRouteConfigurationsList__Output { + 'scoped_route_configurations': (_envoy_api_v2_ScopedRouteConfiguration__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts new file mode 100644 index 00000000..1409cb89 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts @@ -0,0 +1,265 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; +import { ScopedRouteConfigurationsList as _envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList, ScopedRouteConfigurationsList__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList'; +import { ScopedRds as _envoy_config_filter_network_http_connection_manager_v2_ScopedRds, ScopedRds__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRds__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRds'; + +/** + * Specifies the mechanism for constructing key fragments which are composed into scope keys. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder { + /** + * Specifies how a header field's value should be extracted. + */ + 'header_value_extractor'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor); + 'type'?: "header_value_extractor"; +} + +/** + * Specifies the mechanism for constructing key fragments which are composed into scope keys. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder__Output { + /** + * Specifies how a header field's value should be extracted. + */ + 'header_value_extractor'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor__Output); + 'type': "header_value_extractor"; +} + +/** + * Specifies how the value of a header should be extracted. + * The following example maps the structure of a header to the fields in this message. + * + * .. code:: + * + * <0> <1> <-- index + * X-Header: a=b;c=d + * | || | + * | || \----> + * | || + * | |\----> + * | | + * | \----> + * | + * \----> + * + * Each 'a=b' key-value pair constitutes an 'element' of the header field. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor { + /** + * The name of the header field to extract the value from. + */ + 'name'?: (string); + /** + * The element separator (e.g., ';' separates 'a;b;c;d'). + * Default: empty string. This causes the entirety of the header field to be extracted. + * If this field is set to an empty string and 'index' is used in the oneof below, 'index' + * must be set to 0. + */ + 'element_separator'?: (string); + /** + * Specifies the zero based index of the element to extract. + * Note Envoy concatenates multiple values of the same header key into a comma separated + * string, the splitting always happens after the concatenation. + */ + 'index'?: (number); + /** + * Specifies the key value pair to extract the value from. + */ + 'element'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement); + 'extract_type'?: "index"|"element"; +} + +/** + * Specifies how the value of a header should be extracted. + * The following example maps the structure of a header to the fields in this message. + * + * .. code:: + * + * <0> <1> <-- index + * X-Header: a=b;c=d + * | || | + * | || \----> + * | || + * | |\----> + * | | + * | \----> + * | + * \----> + * + * Each 'a=b' key-value pair constitutes an 'element' of the header field. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor__Output { + /** + * The name of the header field to extract the value from. + */ + 'name': (string); + /** + * The element separator (e.g., ';' separates 'a;b;c;d'). + * Default: empty string. This causes the entirety of the header field to be extracted. + * If this field is set to an empty string and 'index' is used in the oneof below, 'index' + * must be set to 0. + */ + 'element_separator': (string); + /** + * Specifies the zero based index of the element to extract. + * Note Envoy concatenates multiple values of the same header key into a comma separated + * string, the splitting always happens after the concatenation. + */ + 'index'?: (number); + /** + * Specifies the key value pair to extract the value from. + */ + 'element'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement__Output); + 'extract_type': "index"|"element"; +} + +/** + * Specifies a header field's key value pair to match on. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement { + /** + * The separator between key and value (e.g., '=' separates 'k=v;...'). + * If an element is an empty string, the element is ignored. + * If an element contains no separator, the whole element is parsed as key and the + * fragment value is an empty string. + * If there are multiple values for a matched key, the first value is returned. + */ + 'separator'?: (string); + /** + * The key to match on. + */ + 'key'?: (string); +} + +/** + * Specifies a header field's key value pair to match on. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement__Output { + /** + * The separator between key and value (e.g., '=' separates 'k=v;...'). + * If an element is an empty string, the element is ignored. + * If an element contains no separator, the whole element is parsed as key and the + * fragment value is an empty string. + * If there are multiple values for a matched key, the first value is returned. + */ + 'separator': (string); + /** + * The key to match on. + */ + 'key': (string); +} + +/** + * Specifies the mechanism for constructing "scope keys" based on HTTP request attributes. These + * keys are matched against a set of :ref:`Key` + * objects assembled from :ref:`ScopedRouteConfiguration` + * messages distributed via SRDS (the Scoped Route Discovery Service) or assigned statically via + * :ref:`scoped_route_configurations_list`. + * + * Upon receiving a request's headers, the Router will build a key using the algorithm specified + * by this message. This key will be used to look up the routing table (i.e., the + * :ref:`RouteConfiguration`) to use for the request. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder { + /** + * The final(built) scope key consists of the ordered union of these fragments, which are compared in order with the + * fragments of a :ref:`ScopedRouteConfiguration`. + * A missing fragment during comparison will make the key invalid, i.e., the computed key doesn't match any key. + */ + 'fragments'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder)[]; +} + +/** + * Specifies the mechanism for constructing "scope keys" based on HTTP request attributes. These + * keys are matched against a set of :ref:`Key` + * objects assembled from :ref:`ScopedRouteConfiguration` + * messages distributed via SRDS (the Scoped Route Discovery Service) or assigned statically via + * :ref:`scoped_route_configurations_list`. + * + * Upon receiving a request's headers, the Router will build a key using the algorithm specified + * by this message. This key will be used to look up the routing table (i.e., the + * :ref:`RouteConfiguration`) to use for the request. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder__Output { + /** + * The final(built) scope key consists of the ordered union of these fragments, which are compared in order with the + * fragments of a :ref:`ScopedRouteConfiguration`. + * A missing fragment during comparison will make the key invalid, i.e., the computed key doesn't match any key. + */ + 'fragments': (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder__Output)[]; +} + +/** + * [#next-free-field: 6] + */ +export interface ScopedRoutes { + /** + * The name assigned to the scoped routing configuration. + */ + 'name'?: (string); + /** + * The algorithm to use for constructing a scope key for each request. + */ + 'scope_key_builder'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder); + /** + * Configuration source specifier for RDS. + * This config source is used to subscribe to RouteConfiguration resources specified in + * ScopedRouteConfiguration messages. + */ + 'rds_config_source'?: (_envoy_api_v2_core_ConfigSource); + /** + * The set of routing scopes corresponding to the HCM. A scope is assigned to a request by + * matching a key constructed from the request's attributes according to the algorithm specified + * by the + * :ref:`ScopeKeyBuilder` + * in this message. + */ + 'scoped_route_configurations_list'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList); + /** + * The set of routing scopes associated with the HCM will be dynamically loaded via the SRDS + * API. A scope is assigned to a request by matching a key constructed from the request's + * attributes according to the algorithm specified by the + * :ref:`ScopeKeyBuilder` + * in this message. + */ + 'scoped_rds'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRds); + 'config_specifier'?: "scoped_route_configurations_list"|"scoped_rds"; +} + +/** + * [#next-free-field: 6] + */ +export interface ScopedRoutes__Output { + /** + * The name assigned to the scoped routing configuration. + */ + 'name': (string); + /** + * The algorithm to use for constructing a scope key for each request. + */ + 'scope_key_builder'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder__Output); + /** + * Configuration source specifier for RDS. + * This config source is used to subscribe to RouteConfiguration resources specified in + * ScopedRouteConfiguration messages. + */ + 'rds_config_source'?: (_envoy_api_v2_core_ConfigSource__Output); + /** + * The set of routing scopes corresponding to the HCM. A scope is assigned to a request by + * matching a key constructed from the request's attributes according to the algorithm specified + * by the + * :ref:`ScopeKeyBuilder` + * in this message. + */ + 'scoped_route_configurations_list'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList__Output); + /** + * The set of routing scopes associated with the HCM will be dynamically loaded via the SRDS + * API. A scope is assigned to a request by matching a key constructed from the request's + * attributes according to the algorithm specified by the + * :ref:`ScopeKeyBuilder` + * in this message. + */ + 'scoped_rds'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRds__Output); + 'config_specifier': "scoped_route_configurations_list"|"scoped_rds"; +} diff --git a/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v2/ApiListener.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts rename to packages/grpc-js-xds/src/generated/envoy/config/listener/v2/ApiListener.ts diff --git a/packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts new file mode 100644 index 00000000..b7ee1c3a --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts @@ -0,0 +1,114 @@ +// Original file: deps/envoy-api/envoy/config/trace/v2/http_tracer.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +/** + * Configuration for an HTTP tracer provider used by Envoy. + * + * The configuration is defined by the + * :ref:`HttpConnectionManager.Tracing ` + * :ref:`provider ` + * field. + */ +export interface _envoy_config_trace_v2_Tracing_Http { + /** + * The name of the HTTP trace driver to instantiate. The name must match a + * supported HTTP trace driver. Built-in trace drivers: + * + * - *envoy.tracers.lightstep* + * - *envoy.tracers.zipkin* + * - *envoy.tracers.dynamic_ot* + * - *envoy.tracers.datadog* + * - *envoy.tracers.opencensus* + * - *envoy.tracers.xray* + */ + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + /** + * Trace driver specific configuration which depends on the driver being instantiated. + * See the trace drivers for examples: + * + * - :ref:`LightstepConfig ` + * - :ref:`ZipkinConfig ` + * - :ref:`DynamicOtConfig ` + * - :ref:`DatadogConfig ` + * - :ref:`OpenCensusConfig ` + * - :ref:`AWS X-Ray ` + */ + 'config_type'?: "config"|"typed_config"; +} + +/** + * Configuration for an HTTP tracer provider used by Envoy. + * + * The configuration is defined by the + * :ref:`HttpConnectionManager.Tracing ` + * :ref:`provider ` + * field. + */ +export interface _envoy_config_trace_v2_Tracing_Http__Output { + /** + * The name of the HTTP trace driver to instantiate. The name must match a + * supported HTTP trace driver. Built-in trace drivers: + * + * - *envoy.tracers.lightstep* + * - *envoy.tracers.zipkin* + * - *envoy.tracers.dynamic_ot* + * - *envoy.tracers.datadog* + * - *envoy.tracers.opencensus* + * - *envoy.tracers.xray* + */ + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Trace driver specific configuration which depends on the driver being instantiated. + * See the trace drivers for examples: + * + * - :ref:`LightstepConfig ` + * - :ref:`ZipkinConfig ` + * - :ref:`DynamicOtConfig ` + * - :ref:`DatadogConfig ` + * - :ref:`OpenCensusConfig ` + * - :ref:`AWS X-Ray ` + */ + 'config_type': "config"|"typed_config"; +} + +/** + * The tracing configuration specifies settings for an HTTP tracer provider used by Envoy. + * + * Envoy may support other tracers in the future, but right now the HTTP tracer is the only one + * supported. + * + * .. attention:: + * + * Use of this message type has been deprecated in favor of direct use of + * :ref:`Tracing.Http `. + */ +export interface Tracing { + /** + * Provides configuration for the HTTP tracer. + */ + 'http'?: (_envoy_config_trace_v2_Tracing_Http); +} + +/** + * The tracing configuration specifies settings for an HTTP tracer provider used by Envoy. + * + * Envoy may support other tracers in the future, but right now the HTTP tracer is the only one + * supported. + * + * .. attention:: + * + * Use of this message type has been deprecated in favor of direct use of + * :ref:`Tracing.Http `. + */ +export interface Tracing__Output { + /** + * Provides configuration for the HTTP tracer. + */ + 'http'?: (_envoy_config_trace_v2_Tracing_Http__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AdsDummy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.ts rename to packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AdsDummy.ts diff --git a/packages/grpc-js/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts similarity index 92% rename from packages/grpc-js/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts rename to packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts index 32cc9ba5..02c0da34 100644 --- a/packages/grpc-js/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/service/discovery/v2/ads.proto -import * as grpc from '../../../../../index' +import * as grpc from '@grpc/grpc-js' import { DeltaDiscoveryRequest as _envoy_api_v2_DeltaDiscoveryRequest, DeltaDiscoveryRequest__Output as _envoy_api_v2_DeltaDiscoveryRequest__Output } from '../../../../envoy/api/v2/DeltaDiscoveryRequest'; import { DeltaDiscoveryResponse as _envoy_api_v2_DeltaDiscoveryResponse, DeltaDiscoveryResponse__Output as _envoy_api_v2_DeltaDiscoveryResponse__Output } from '../../../../envoy/api/v2/DeltaDiscoveryResponse'; import { DiscoveryRequest as _envoy_api_v2_DiscoveryRequest, DiscoveryRequest__Output as _envoy_api_v2_DiscoveryRequest__Output } from '../../../../envoy/api/v2/DiscoveryRequest'; @@ -41,12 +41,12 @@ export interface AggregatedDiscoveryServiceClient extends grpc.Client { * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover * the multiplexed singleton APIs at the Envoy instance and management server. */ -export interface AggregatedDiscoveryServiceHandlers { - DeltaAggregatedResources(call: grpc.ServerDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse__Output>): void; +export interface AggregatedDiscoveryServiceHandlers extends grpc.UntypedServiceImplementation { + DeltaAggregatedResources(call: grpc.ServerDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest__Output, _envoy_api_v2_DeltaDiscoveryResponse>): void; /** * This is a gRPC-only API. */ - StreamAggregatedResources(call: grpc.ServerDuplexStream<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse__Output>): void; + StreamAggregatedResources(call: grpc.ServerDuplexStream<_envoy_api_v2_DiscoveryRequest__Output, _envoy_api_v2_DiscoveryResponse>): void; } diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts new file mode 100644 index 00000000..7db2bad1 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts @@ -0,0 +1,108 @@ +// Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto + +import * as grpc from '@grpc/grpc-js' +import { LoadStatsRequest as _envoy_service_load_stats_v2_LoadStatsRequest, LoadStatsRequest__Output as _envoy_service_load_stats_v2_LoadStatsRequest__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsRequest'; +import { LoadStatsResponse as _envoy_service_load_stats_v2_LoadStatsResponse, LoadStatsResponse__Output as _envoy_service_load_stats_v2_LoadStatsResponse__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsResponse'; + +export interface LoadReportingServiceClient extends grpc.Client { + /** + * Advanced API to allow for multi-dimensional load balancing by remote + * server. For receiving LB assignments, the steps are: + * 1, The management server is configured with per cluster/zone/load metric + * capacity configuration. The capacity configuration definition is + * outside of the scope of this document. + * 2. Envoy issues a standard {Stream,Fetch}Endpoints request for the clusters + * to balance. + * + * Independently, Envoy will initiate a StreamLoadStats bidi stream with a + * management server: + * 1. Once a connection establishes, the management server publishes a + * LoadStatsResponse for all clusters it is interested in learning load + * stats about. + * 2. For each cluster, Envoy load balances incoming traffic to upstream hosts + * based on per-zone weights and/or per-instance weights (if specified) + * based on intra-zone LbPolicy. This information comes from the above + * {Stream,Fetch}Endpoints. + * 3. When upstream hosts reply, they optionally add header with ASCII representation of EndpointLoadMetricStats. + * 4. Envoy aggregates load reports over the period of time given to it in + * LoadStatsResponse.load_reporting_interval. This includes aggregation + * stats Envoy maintains by itself (total_requests, rpc_errors etc.) as + * well as load metrics from upstream hosts. + * 5. When the timer of load_reporting_interval expires, Envoy sends new + * LoadStatsRequest filled with load reports for each cluster. + * 6. The management server uses the load reports from all reported Envoys + * from around the world, computes global assignment and prepares traffic + * assignment destined for each zone Envoys are located in. Goto 2. + */ + StreamLoadStats(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>; + StreamLoadStats(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>; + /** + * Advanced API to allow for multi-dimensional load balancing by remote + * server. For receiving LB assignments, the steps are: + * 1, The management server is configured with per cluster/zone/load metric + * capacity configuration. The capacity configuration definition is + * outside of the scope of this document. + * 2. Envoy issues a standard {Stream,Fetch}Endpoints request for the clusters + * to balance. + * + * Independently, Envoy will initiate a StreamLoadStats bidi stream with a + * management server: + * 1. Once a connection establishes, the management server publishes a + * LoadStatsResponse for all clusters it is interested in learning load + * stats about. + * 2. For each cluster, Envoy load balances incoming traffic to upstream hosts + * based on per-zone weights and/or per-instance weights (if specified) + * based on intra-zone LbPolicy. This information comes from the above + * {Stream,Fetch}Endpoints. + * 3. When upstream hosts reply, they optionally add header with ASCII representation of EndpointLoadMetricStats. + * 4. Envoy aggregates load reports over the period of time given to it in + * LoadStatsResponse.load_reporting_interval. This includes aggregation + * stats Envoy maintains by itself (total_requests, rpc_errors etc.) as + * well as load metrics from upstream hosts. + * 5. When the timer of load_reporting_interval expires, Envoy sends new + * LoadStatsRequest filled with load reports for each cluster. + * 6. The management server uses the load reports from all reported Envoys + * from around the world, computes global assignment and prepares traffic + * assignment destined for each zone Envoys are located in. Goto 2. + */ + streamLoadStats(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>; + streamLoadStats(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>; + +} + +export interface LoadReportingServiceHandlers extends grpc.UntypedServiceImplementation { + /** + * Advanced API to allow for multi-dimensional load balancing by remote + * server. For receiving LB assignments, the steps are: + * 1, The management server is configured with per cluster/zone/load metric + * capacity configuration. The capacity configuration definition is + * outside of the scope of this document. + * 2. Envoy issues a standard {Stream,Fetch}Endpoints request for the clusters + * to balance. + * + * Independently, Envoy will initiate a StreamLoadStats bidi stream with a + * management server: + * 1. Once a connection establishes, the management server publishes a + * LoadStatsResponse for all clusters it is interested in learning load + * stats about. + * 2. For each cluster, Envoy load balances incoming traffic to upstream hosts + * based on per-zone weights and/or per-instance weights (if specified) + * based on intra-zone LbPolicy. This information comes from the above + * {Stream,Fetch}Endpoints. + * 3. When upstream hosts reply, they optionally add header with ASCII representation of EndpointLoadMetricStats. + * 4. Envoy aggregates load reports over the period of time given to it in + * LoadStatsResponse.load_reporting_interval. This includes aggregation + * stats Envoy maintains by itself (total_requests, rpc_errors etc.) as + * well as load metrics from upstream hosts. + * 5. When the timer of load_reporting_interval expires, Envoy sends new + * LoadStatsRequest filled with load reports for each cluster. + * 6. The management server uses the load reports from all reported Envoys + * from around the world, computes global assignment and prepares traffic + * assignment destined for each zone Envoys are located in. Goto 2. + */ + StreamLoadStats(call: grpc.ServerDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest__Output, _envoy_service_load_stats_v2_LoadStatsResponse>): void; + +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts new file mode 100644 index 00000000..f2c2393c --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts @@ -0,0 +1,34 @@ +// Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto + +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../../envoy/api/v2/core/Node'; +import { ClusterStats as _envoy_api_v2_endpoint_ClusterStats, ClusterStats__Output as _envoy_api_v2_endpoint_ClusterStats__Output } from '../../../../envoy/api/v2/endpoint/ClusterStats'; + +/** + * A load report Envoy sends to the management server. + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + */ +export interface LoadStatsRequest { + /** + * Node identifier for Envoy instance. + */ + 'node'?: (_envoy_api_v2_core_Node); + /** + * A list of load stats to report. + */ + 'cluster_stats'?: (_envoy_api_v2_endpoint_ClusterStats)[]; +} + +/** + * A load report Envoy sends to the management server. + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + */ +export interface LoadStatsRequest__Output { + /** + * Node identifier for Envoy instance. + */ + 'node'?: (_envoy_api_v2_core_Node__Output); + /** + * A list of load stats to report. + */ + 'cluster_stats': (_envoy_api_v2_endpoint_ClusterStats__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts new file mode 100644 index 00000000..9326d869 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts @@ -0,0 +1,71 @@ +// Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto + +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; + +/** + * The management server sends envoy a LoadStatsResponse with all clusters it + * is interested in learning load stats about. + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + */ +export interface LoadStatsResponse { + /** + * Clusters to report stats for. + * Not populated if *send_all_clusters* is true. + */ + 'clusters'?: (string)[]; + /** + * The minimum interval of time to collect stats over. This is only a minimum for two reasons: + * 1. There may be some delay from when the timer fires until stats sampling occurs. + * 2. For clusters that were already feature in the previous *LoadStatsResponse*, any traffic + * that is observed in between the corresponding previous *LoadStatsRequest* and this + * *LoadStatsResponse* will also be accumulated and billed to the cluster. This avoids a period + * of inobservability that might otherwise exists between the messages. New clusters are not + * subject to this consideration. + */ + 'load_reporting_interval'?: (_google_protobuf_Duration); + /** + * Set to *true* if the management server supports endpoint granularity + * report. + */ + 'report_endpoint_granularity'?: (boolean); + /** + * If true, the client should send all clusters it knows about. + * Only clients that advertise the "envoy.lrs.supports_send_all_clusters" capability in their + * :ref:`client_features` field will honor this field. + */ + 'send_all_clusters'?: (boolean); +} + +/** + * The management server sends envoy a LoadStatsResponse with all clusters it + * is interested in learning load stats about. + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + */ +export interface LoadStatsResponse__Output { + /** + * Clusters to report stats for. + * Not populated if *send_all_clusters* is true. + */ + 'clusters': (string)[]; + /** + * The minimum interval of time to collect stats over. This is only a minimum for two reasons: + * 1. There may be some delay from when the timer fires until stats sampling occurs. + * 2. For clusters that were already feature in the previous *LoadStatsResponse*, any traffic + * that is observed in between the corresponding previous *LoadStatsRequest* and this + * *LoadStatsResponse* will also be accumulated and billed to the cluster. This avoids a period + * of inobservability that might otherwise exists between the messages. New clusters are not + * subject to this consideration. + */ + 'load_reporting_interval'?: (_google_protobuf_Duration__Output); + /** + * Set to *true* if the management server supports endpoint granularity + * report. + */ + 'report_endpoint_granularity': (boolean); + /** + * If true, the client should send all clusters it knows about. + * Only clients that advertise the "envoy.lrs.supports_send_all_clusters" capability in their + * :ref:`client_features` field will honor this field. + */ + 'send_all_clusters': (boolean); +} diff --git a/packages/grpc-js/src/generated/envoy/type/CodecClientType.ts b/packages/grpc-js-xds/src/generated/envoy/type/CodecClientType.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/CodecClientType.ts rename to packages/grpc-js-xds/src/generated/envoy/type/CodecClientType.ts diff --git a/packages/grpc-js/src/generated/envoy/type/DoubleRange.ts b/packages/grpc-js-xds/src/generated/envoy/type/DoubleRange.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/DoubleRange.ts rename to packages/grpc-js-xds/src/generated/envoy/type/DoubleRange.ts diff --git a/packages/grpc-js/src/generated/envoy/type/FractionalPercent.ts b/packages/grpc-js-xds/src/generated/envoy/type/FractionalPercent.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/FractionalPercent.ts rename to packages/grpc-js-xds/src/generated/envoy/type/FractionalPercent.ts diff --git a/packages/grpc-js/src/generated/envoy/type/Int32Range.ts b/packages/grpc-js-xds/src/generated/envoy/type/Int32Range.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/Int32Range.ts rename to packages/grpc-js-xds/src/generated/envoy/type/Int32Range.ts diff --git a/packages/grpc-js/src/generated/envoy/type/Int64Range.ts b/packages/grpc-js-xds/src/generated/envoy/type/Int64Range.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/Int64Range.ts rename to packages/grpc-js-xds/src/generated/envoy/type/Int64Range.ts diff --git a/packages/grpc-js/src/generated/envoy/type/Percent.ts b/packages/grpc-js-xds/src/generated/envoy/type/Percent.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/Percent.ts rename to packages/grpc-js-xds/src/generated/envoy/type/Percent.ts diff --git a/packages/grpc-js/src/generated/envoy/type/SemanticVersion.ts b/packages/grpc-js-xds/src/generated/envoy/type/SemanticVersion.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/SemanticVersion.ts rename to packages/grpc-js-xds/src/generated/envoy/type/SemanticVersion.ts diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/ListStringMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/type/matcher/ListStringMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts rename to packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/StringMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/type/matcher/StringMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.ts b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKey.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.ts rename to packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKey.ts diff --git a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKind.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts rename to packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKind.ts diff --git a/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts b/packages/grpc-js-xds/src/generated/envoy/type/tracing/v2/CustomTag.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts rename to packages/grpc-js-xds/src/generated/envoy/type/tracing/v2/CustomTag.ts diff --git a/packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts b/packages/grpc-js-xds/src/generated/google/api/CustomHttpPattern.ts similarity index 100% rename from packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts rename to packages/grpc-js-xds/src/generated/google/api/CustomHttpPattern.ts diff --git a/packages/grpc-js/src/generated/google/api/Http.ts b/packages/grpc-js-xds/src/generated/google/api/Http.ts similarity index 100% rename from packages/grpc-js/src/generated/google/api/Http.ts rename to packages/grpc-js-xds/src/generated/google/api/Http.ts diff --git a/packages/grpc-js/src/generated/google/api/HttpRule.ts b/packages/grpc-js-xds/src/generated/google/api/HttpRule.ts similarity index 100% rename from packages/grpc-js/src/generated/google/api/HttpRule.ts rename to packages/grpc-js-xds/src/generated/google/api/HttpRule.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Any.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Any.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Any.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Any.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/BoolValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/BoolValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/BoolValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/BoolValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/BytesValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/BytesValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/BytesValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/BytesValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/DescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/DescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/DoubleValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/DoubleValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/DoubleValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/DoubleValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Duration.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Duration.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Duration.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Duration.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Empty.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Empty.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Empty.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Empty.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/EnumDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/EnumValueDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/FieldDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorSet.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorSet.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FileOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FileOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FloatValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FloatValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FloatValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/FloatValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.ts b/packages/grpc-js-xds/src/generated/google/protobuf/GeneratedCodeInfo.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/GeneratedCodeInfo.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Int32Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Int32Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Int32Value.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Int32Value.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Int64Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Int64Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Int64Value.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Int64Value.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/ListValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/ListValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/ListValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/ListValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MethodDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/MethodDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts similarity index 68% rename from packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts index a5edbd8b..982c7d5d 100644 --- a/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts @@ -1,16 +1,13 @@ // Original file: null import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; export interface MethodOptions { 'deprecated'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; - '.google.api.http'?: (_google_api_HttpRule); } export interface MethodOptions__Output { 'deprecated': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.google.api.http'?: (_google_api_HttpRule__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/NullValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/NullValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/NullValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/NullValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/OneofDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/OneofDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/OneofOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/OneofOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/OneofOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/OneofOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/ServiceDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/ServiceDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/ServiceOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/ServiceOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/ServiceOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/ServiceOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.ts b/packages/grpc-js-xds/src/generated/google/protobuf/SourceCodeInfo.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/SourceCodeInfo.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/StringValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/StringValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/StringValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/StringValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Struct.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Struct.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Struct.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Struct.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Timestamp.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Timestamp.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Timestamp.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Timestamp.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/UInt32Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/UInt32Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/UInt32Value.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/UInt32Value.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/UInt64Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/UInt64Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/UInt64Value.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/UInt64Value.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.ts b/packages/grpc-js-xds/src/generated/google/protobuf/UninterpretedOption.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/UninterpretedOption.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Value.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Value.ts diff --git a/packages/grpc-js/src/generated/google/rpc/Status.ts b/packages/grpc-js-xds/src/generated/google/rpc/Status.ts similarity index 100% rename from packages/grpc-js/src/generated/google/rpc/Status.ts rename to packages/grpc-js-xds/src/generated/google/rpc/Status.ts diff --git a/packages/grpc-js-xds/src/generated/http_connection_manager.ts b/packages/grpc-js-xds/src/generated/http_connection_manager.ts new file mode 100644 index 00000000..5a90451a --- /dev/null +++ b/packages/grpc-js-xds/src/generated/http_connection_manager.ts @@ -0,0 +1,228 @@ +import * as grpc from '@grpc/grpc-js'; +import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + + +type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; +type SubtypeConstructor = { + new(...args: ConstructorArguments): Subtype; +}; + +export interface ProtoGrpcType { + envoy: { + annotations: { + } + api: { + v2: { + RouteConfiguration: MessageTypeDefinition + ScopedRouteConfiguration: MessageTypeDefinition + Vhds: MessageTypeDefinition + core: { + Address: MessageTypeDefinition + AggregatedConfigSource: MessageTypeDefinition + ApiConfigSource: MessageTypeDefinition + ApiVersion: EnumTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ConfigSource: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition + Extension: MessageTypeDefinition + GrpcProtocolOptions: MessageTypeDefinition + GrpcService: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + Http1ProtocolOptions: MessageTypeDefinition + Http2ProtocolOptions: MessageTypeDefinition + HttpProtocolOptions: MessageTypeDefinition + HttpUri: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition + RateLimitSettings: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + SelfConfigSource: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + SocketOption: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TcpProtocolOptions: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition + UpstreamHttpProtocolOptions: MessageTypeDefinition + } + route: { + CorsPolicy: MessageTypeDefinition + Decorator: MessageTypeDefinition + DirectResponseAction: MessageTypeDefinition + FilterAction: MessageTypeDefinition + HeaderMatcher: MessageTypeDefinition + HedgePolicy: MessageTypeDefinition + QueryParameterMatcher: MessageTypeDefinition + RateLimit: MessageTypeDefinition + RedirectAction: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + Route: MessageTypeDefinition + RouteAction: MessageTypeDefinition + RouteMatch: MessageTypeDefinition + Tracing: MessageTypeDefinition + VirtualCluster: MessageTypeDefinition + VirtualHost: MessageTypeDefinition + WeightedCluster: MessageTypeDefinition + } + } + } + config: { + filter: { + accesslog: { + v2: { + AccessLog: MessageTypeDefinition + AccessLogFilter: MessageTypeDefinition + AndFilter: MessageTypeDefinition + ComparisonFilter: MessageTypeDefinition + DurationFilter: MessageTypeDefinition + ExtensionFilter: MessageTypeDefinition + GrpcStatusFilter: MessageTypeDefinition + HeaderFilter: MessageTypeDefinition + NotHealthCheckFilter: MessageTypeDefinition + OrFilter: MessageTypeDefinition + ResponseFlagFilter: MessageTypeDefinition + RuntimeFilter: MessageTypeDefinition + StatusCodeFilter: MessageTypeDefinition + TraceableFilter: MessageTypeDefinition + } + } + network: { + http_connection_manager: { + v2: { + HttpConnectionManager: MessageTypeDefinition + HttpFilter: MessageTypeDefinition + Rds: MessageTypeDefinition + RequestIDExtension: MessageTypeDefinition + ScopedRds: MessageTypeDefinition + ScopedRouteConfigurationsList: MessageTypeDefinition + ScopedRoutes: MessageTypeDefinition + } + } + } + } + trace: { + v2: { + Tracing: MessageTypeDefinition + } + } + } + type: { + DoubleRange: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + matcher: { + ListStringMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + } + metadata: { + v2: { + MetadataKey: MessageTypeDefinition + MetadataKind: MessageTypeDefinition + } + } + tracing: { + v2: { + CustomTag: MessageTypeDefinition + } + } + } + } + google: { + protobuf: { + Any: MessageTypeDefinition + BoolValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition + Empty: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileOptions: MessageTypeDefinition + FloatValue: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + ListValue: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + StringValue: MessageTypeDefinition + Struct: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + Value: MessageTypeDefinition + } + } + udpa: { + annotations: { + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + MapRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + } +} + diff --git a/packages/grpc-js/src/generated/listener.ts b/packages/grpc-js-xds/src/generated/listener.ts similarity index 99% rename from packages/grpc-js/src/generated/listener.ts rename to packages/grpc-js-xds/src/generated/listener.ts index 040c1d52..57daeffd 100644 --- a/packages/grpc-js/src/generated/listener.ts +++ b/packages/grpc-js-xds/src/generated/listener.ts @@ -1,11 +1,11 @@ -import * as grpc from '../index'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { envoy: { diff --git a/packages/grpc-js-xds/src/generated/lrs.ts b/packages/grpc-js-xds/src/generated/lrs.ts new file mode 100644 index 00000000..56ada2f3 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/lrs.ts @@ -0,0 +1,146 @@ +import * as grpc from '@grpc/grpc-js'; +import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + +import { LoadReportingServiceClient as _envoy_service_load_stats_v2_LoadReportingServiceClient } from './envoy/service/load_stats/v2/LoadReportingService'; + +type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; +type SubtypeConstructor = { + new(...args: ConstructorArguments): Subtype; +}; + +export interface ProtoGrpcType { + envoy: { + api: { + v2: { + core: { + Address: MessageTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition + Extension: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + HttpUri: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + SocketOption: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition + } + endpoint: { + ClusterStats: MessageTypeDefinition + EndpointLoadMetricStats: MessageTypeDefinition + UpstreamEndpointStats: MessageTypeDefinition + UpstreamLocalityStats: MessageTypeDefinition + } + } + } + service: { + load_stats: { + v2: { + LoadReportingService: SubtypeConstructor & { service: ServiceDefinition } + LoadStatsRequest: MessageTypeDefinition + LoadStatsResponse: MessageTypeDefinition + } + } + } + type: { + FractionalPercent: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + } + } + google: { + protobuf: { + Any: MessageTypeDefinition + BoolValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileOptions: MessageTypeDefinition + FloatValue: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + ListValue: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + StringValue: MessageTypeDefinition + Struct: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + Value: MessageTypeDefinition + } + } + udpa: { + annotations: { + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + MapRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + } +} + diff --git a/packages/grpc-js/src/generated/route.ts b/packages/grpc-js-xds/src/generated/route.ts similarity index 99% rename from packages/grpc-js/src/generated/route.ts rename to packages/grpc-js-xds/src/generated/route.ts index 5b251477..40bcdd55 100644 --- a/packages/grpc-js/src/generated/route.ts +++ b/packages/grpc-js-xds/src/generated/route.ts @@ -1,11 +1,11 @@ -import * as grpc from '../index'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { envoy: { diff --git a/packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/FieldMigrateAnnotation.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.ts rename to packages/grpc-js-xds/src/generated/udpa/annotations/FieldMigrateAnnotation.ts diff --git a/packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/FileMigrateAnnotation.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.ts rename to packages/grpc-js-xds/src/generated/udpa/annotations/FileMigrateAnnotation.ts diff --git a/packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/MigrateAnnotation.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.ts rename to packages/grpc-js-xds/src/generated/udpa/annotations/MigrateAnnotation.ts diff --git a/packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/PackageVersionStatus.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.ts rename to packages/grpc-js-xds/src/generated/udpa/annotations/PackageVersionStatus.ts diff --git a/packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/StatusAnnotation.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.ts rename to packages/grpc-js-xds/src/generated/udpa/annotations/StatusAnnotation.ts diff --git a/packages/grpc-js/src/generated/validate/AnyRules.ts b/packages/grpc-js-xds/src/generated/validate/AnyRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/AnyRules.ts rename to packages/grpc-js-xds/src/generated/validate/AnyRules.ts diff --git a/packages/grpc-js/src/generated/validate/BoolRules.ts b/packages/grpc-js-xds/src/generated/validate/BoolRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/BoolRules.ts rename to packages/grpc-js-xds/src/generated/validate/BoolRules.ts diff --git a/packages/grpc-js/src/generated/validate/BytesRules.ts b/packages/grpc-js-xds/src/generated/validate/BytesRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/BytesRules.ts rename to packages/grpc-js-xds/src/generated/validate/BytesRules.ts diff --git a/packages/grpc-js/src/generated/validate/DoubleRules.ts b/packages/grpc-js-xds/src/generated/validate/DoubleRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/DoubleRules.ts rename to packages/grpc-js-xds/src/generated/validate/DoubleRules.ts diff --git a/packages/grpc-js/src/generated/validate/DurationRules.ts b/packages/grpc-js-xds/src/generated/validate/DurationRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/DurationRules.ts rename to packages/grpc-js-xds/src/generated/validate/DurationRules.ts diff --git a/packages/grpc-js/src/generated/validate/EnumRules.ts b/packages/grpc-js-xds/src/generated/validate/EnumRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/EnumRules.ts rename to packages/grpc-js-xds/src/generated/validate/EnumRules.ts diff --git a/packages/grpc-js/src/generated/validate/FieldRules.ts b/packages/grpc-js-xds/src/generated/validate/FieldRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/FieldRules.ts rename to packages/grpc-js-xds/src/generated/validate/FieldRules.ts diff --git a/packages/grpc-js/src/generated/validate/Fixed32Rules.ts b/packages/grpc-js-xds/src/generated/validate/Fixed32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/Fixed32Rules.ts rename to packages/grpc-js-xds/src/generated/validate/Fixed32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/Fixed64Rules.ts b/packages/grpc-js-xds/src/generated/validate/Fixed64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/Fixed64Rules.ts rename to packages/grpc-js-xds/src/generated/validate/Fixed64Rules.ts diff --git a/packages/grpc-js/src/generated/validate/FloatRules.ts b/packages/grpc-js-xds/src/generated/validate/FloatRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/FloatRules.ts rename to packages/grpc-js-xds/src/generated/validate/FloatRules.ts diff --git a/packages/grpc-js/src/generated/validate/Int32Rules.ts b/packages/grpc-js-xds/src/generated/validate/Int32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/Int32Rules.ts rename to packages/grpc-js-xds/src/generated/validate/Int32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/Int64Rules.ts b/packages/grpc-js-xds/src/generated/validate/Int64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/Int64Rules.ts rename to packages/grpc-js-xds/src/generated/validate/Int64Rules.ts diff --git a/packages/grpc-js/src/generated/validate/KnownRegex.ts b/packages/grpc-js-xds/src/generated/validate/KnownRegex.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/KnownRegex.ts rename to packages/grpc-js-xds/src/generated/validate/KnownRegex.ts diff --git a/packages/grpc-js/src/generated/validate/MapRules.ts b/packages/grpc-js-xds/src/generated/validate/MapRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/MapRules.ts rename to packages/grpc-js-xds/src/generated/validate/MapRules.ts diff --git a/packages/grpc-js/src/generated/validate/MessageRules.ts b/packages/grpc-js-xds/src/generated/validate/MessageRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/MessageRules.ts rename to packages/grpc-js-xds/src/generated/validate/MessageRules.ts diff --git a/packages/grpc-js/src/generated/validate/RepeatedRules.ts b/packages/grpc-js-xds/src/generated/validate/RepeatedRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/RepeatedRules.ts rename to packages/grpc-js-xds/src/generated/validate/RepeatedRules.ts diff --git a/packages/grpc-js/src/generated/validate/SFixed32Rules.ts b/packages/grpc-js-xds/src/generated/validate/SFixed32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/SFixed32Rules.ts rename to packages/grpc-js-xds/src/generated/validate/SFixed32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/SFixed64Rules.ts b/packages/grpc-js-xds/src/generated/validate/SFixed64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/SFixed64Rules.ts rename to packages/grpc-js-xds/src/generated/validate/SFixed64Rules.ts diff --git a/packages/grpc-js/src/generated/validate/SInt32Rules.ts b/packages/grpc-js-xds/src/generated/validate/SInt32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/SInt32Rules.ts rename to packages/grpc-js-xds/src/generated/validate/SInt32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/SInt64Rules.ts b/packages/grpc-js-xds/src/generated/validate/SInt64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/SInt64Rules.ts rename to packages/grpc-js-xds/src/generated/validate/SInt64Rules.ts diff --git a/packages/grpc-js/src/generated/validate/StringRules.ts b/packages/grpc-js-xds/src/generated/validate/StringRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/StringRules.ts rename to packages/grpc-js-xds/src/generated/validate/StringRules.ts diff --git a/packages/grpc-js/src/generated/validate/TimestampRules.ts b/packages/grpc-js-xds/src/generated/validate/TimestampRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/TimestampRules.ts rename to packages/grpc-js-xds/src/generated/validate/TimestampRules.ts diff --git a/packages/grpc-js/src/generated/validate/UInt32Rules.ts b/packages/grpc-js-xds/src/generated/validate/UInt32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/UInt32Rules.ts rename to packages/grpc-js-xds/src/generated/validate/UInt32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/UInt64Rules.ts b/packages/grpc-js-xds/src/generated/validate/UInt64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/UInt64Rules.ts rename to packages/grpc-js-xds/src/generated/validate/UInt64Rules.ts diff --git a/packages/grpc-js-xds/src/index.ts b/packages/grpc-js-xds/src/index.ts new file mode 100644 index 00000000..06bea990 --- /dev/null +++ b/packages/grpc-js-xds/src/index.ts @@ -0,0 +1,35 @@ +/* + * Copyright 2020 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. + * + */ + +import * as resolver_xds from './resolver-xds'; +import * as load_balancer_cds from './load-balancer-cds'; +import * as load_balancer_eds from './load-balancer-eds'; +import * as load_balancer_lrs from './load-balancer-lrs'; +import * as load_balancer_priority from './load-balancer-priority'; +import * as load_balancer_weighted_target from './load-balancer-weighted-target'; + +/** + * Register the "xds:" name scheme with the @grpc/grpc-js library. + */ +export function register() { + resolver_xds.setup(); + load_balancer_cds.setup(); + load_balancer_eds.setup(); + load_balancer_lrs.setup(); + load_balancer_priority.setup(); + load_balancer_weighted_target.setup(); +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/load-balancer-cds.ts b/packages/grpc-js-xds/src/load-balancer-cds.ts new file mode 100644 index 00000000..a2961927 --- /dev/null +++ b/packages/grpc-js-xds/src/load-balancer-cds.ts @@ -0,0 +1,182 @@ +/* + * Copyright 2020 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. + * + */ + +import { connectivityState, status, Metadata, logVerbosity, experimental } from '@grpc/grpc-js'; +import { XdsClient, Watcher } from './xds-client'; +import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; +import SubchannelAddress = experimental.SubchannelAddress; +import UnavailablePicker = experimental.UnavailablePicker; +import ChildLoadBalancerHandler = experimental.ChildLoadBalancerHandler; +import LoadBalancer = experimental.LoadBalancer; +import ChannelControlHelper = experimental.ChannelControlHelper; +import registerLoadBalancerType = experimental.registerLoadBalancerType; +import LoadBalancingConfig = experimental.LoadBalancingConfig; +import { EdsLoadBalancingConfig } from './load-balancer-eds'; + +const TRACER_NAME = 'cds_balancer'; + +function trace(text: string): void { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); +} + +const TYPE_NAME = 'cds'; + +export class CdsLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + + toJsonObject(): object { + return { + [TYPE_NAME]: { + cluster: this.cluster + } + } + } + + constructor(private cluster: string) {} + + getCluster() { + return this.cluster; + } + + static createFromJson(obj: any): CdsLoadBalancingConfig { + if ('cluster' in obj) { + return new CdsLoadBalancingConfig(obj.cluster); + } else { + throw new Error('Missing "cluster" in cds load balancing config'); + } + } +} + +export class CdsLoadBalancer implements LoadBalancer { + private childBalancer: ChildLoadBalancerHandler; + private xdsClient: XdsClient | null = null; + private watcher: Watcher; + + private isWatcherActive = false; + + private latestCdsUpdate: Cluster__Output | null = null; + + private latestConfig: CdsLoadBalancingConfig | null = null; + private latestAttributes: { [key: string]: unknown } = {}; + + constructor(private readonly channelControlHelper: ChannelControlHelper) { + this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper); + this.watcher = { + onValidUpdate: (update) => { + this.latestCdsUpdate = update; + /* the lrs_server.self field indicates that the same server should be + * used for load reporting as for other xDS operations. Setting + * lrsLoadReportingServerName to the empty string sets that behavior. + * Otherwise, if the field is omitted, load reporting is disabled. */ + const edsConfig: EdsLoadBalancingConfig = new EdsLoadBalancingConfig(update.name, [], [], update.eds_cluster_config!.service_name === '' ? undefined : update.eds_cluster_config!.service_name, update.lrs_server?.self ? '' : undefined); + trace('Child update EDS config: ' + JSON.stringify(edsConfig)); + this.childBalancer.updateAddressList( + [], + edsConfig, + this.latestAttributes + ); + }, + onResourceDoesNotExist: () => { + this.isWatcherActive = false; + this.channelControlHelper.updateState(connectivityState.TRANSIENT_FAILURE, new UnavailablePicker({code: status.UNAVAILABLE, details: 'CDS resource does not exist', metadata: new Metadata()})); + this.childBalancer.destroy(); + }, + onTransientError: (statusObj) => { + if (this.latestCdsUpdate === null) { + channelControlHelper.updateState( + connectivityState.TRANSIENT_FAILURE, + new UnavailablePicker({ + code: status.UNAVAILABLE, + details: `xDS request failed with error ${statusObj.details}`, + metadata: new Metadata(), + }) + ); + } + }, + }; + } + + updateAddressList( + addressList: SubchannelAddress[], + lbConfig: LoadBalancingConfig, + attributes: { [key: string]: unknown } + ): void { + if (!(lbConfig instanceof CdsLoadBalancingConfig)) { + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig, undefined, 2)); + return; + } + if (!(attributes.xdsClient instanceof XdsClient)) { + trace('Discarding address list update missing xdsClient attribute'); + return; + } + trace('Received update with config ' + JSON.stringify(lbConfig, undefined, 2)); + this.xdsClient = attributes.xdsClient; + this.latestAttributes = attributes; + + /* If the cluster is changing, disable the old watcher before adding the new + * one */ + if ( + this.isWatcherActive && + this.latestConfig?.getCluster() !== lbConfig.getCluster() + ) { + trace('Removing old cluster watcher for cluster name ' + this.latestConfig!.getCluster()); + this.xdsClient.removeClusterWatcher( + this.latestConfig!.getCluster(), + this.watcher + ); + /* Setting isWatcherActive to false here lets us have one code path for + * calling addClusterWatcher */ + this.isWatcherActive = false; + /* If we have a new name, the latestCdsUpdate does not correspond to + * the new config, so it is no longer valid */ + this.latestCdsUpdate = null; + } + + this.latestConfig = lbConfig; + + if (!this.isWatcherActive) { + trace('Adding new cluster watcher for cluster name ' + lbConfig.getCluster()); + this.xdsClient.addClusterWatcher(lbConfig.getCluster(), this.watcher); + this.isWatcherActive = true; + } + } + exitIdle(): void { + this.childBalancer.exitIdle(); + } + resetBackoff(): void { + this.childBalancer.resetBackoff(); + } + destroy(): void { + trace('Destroying load balancer with cluster name ' + this.latestConfig?.getCluster()); + this.childBalancer.destroy(); + if (this.isWatcherActive) { + this.xdsClient?.removeClusterWatcher( + this.latestConfig!.getCluster(), + this.watcher + ); + } + } + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup() { + registerLoadBalancerType(TYPE_NAME, CdsLoadBalancer, CdsLoadBalancingConfig); +} diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts new file mode 100644 index 00000000..8919f317 --- /dev/null +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -0,0 +1,494 @@ +/* + * Copyright 2020 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. + * + */ + +import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity as LogVerbosity, experimental } from '@grpc/grpc-js'; +import { XdsClient, Watcher, XdsClusterDropStats } from './xds-client'; +import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; +import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; +import { LocalitySubchannelAddress, PriorityChild, PriorityLoadBalancingConfig } from './load-balancer-priority'; +import LoadBalancer = experimental.LoadBalancer; +import ChannelControlHelper = experimental.ChannelControlHelper; +import registerLoadBalancerType = experimental.registerLoadBalancerType; +import LoadBalancingConfig = experimental.LoadBalancingConfig; +import SubchannelAddress = experimental.SubchannelAddress; +import subchannelAddressToString = experimental.subchannelAddressToString; +import ChildLoadBalancerHandler = experimental.ChildLoadBalancerHandler; +import UnavailablePicker = experimental.UnavailablePicker; +import Picker = experimental.Picker; +import PickResultType = experimental.PickResultType; +import { validateLoadBalancingConfig } from '@grpc/grpc-js/build/src/experimental'; +import { WeightedTarget, WeightedTargetLoadBalancingConfig } from './load-balancer-weighted-target'; +import { LrsLoadBalancingConfig } from './load-balancer-lrs'; + +const TRACER_NAME = 'eds_balancer'; + +function trace(text: string): void { + experimental.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} + +const TYPE_NAME = 'eds'; + +function localityToName(locality: Locality__Output) { + return `{region=${locality.region},zone=${locality.zone},sub_zone=${locality.sub_zone}}`; +} + +export class EdsLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + toJsonObject(): object { + const jsonObj: {[key: string]: any} = { + cluster: this.cluster, + locality_picking_policy: this.localityPickingPolicy.map(policy => policy.toJsonObject()), + endpoint_picking_policy: this.endpointPickingPolicy.map(policy => policy.toJsonObject()) + }; + if (this.edsServiceName !== undefined) { + jsonObj.eds_service_name = this.edsServiceName; + } + if (this.lrsLoadReportingServerName !== undefined) { + jsonObj.lrs_load_reporting_server_name = this.lrsLoadReportingServerName; + } + return { + [TYPE_NAME]: jsonObj + }; + } + + constructor(private cluster: string, private localityPickingPolicy: LoadBalancingConfig[], private endpointPickingPolicy: LoadBalancingConfig[], private edsServiceName?: string, private lrsLoadReportingServerName?: string) { + + } + + getCluster() { + return this.cluster; + } + + getLocalityPickingPolicy() { + return this.localityPickingPolicy; + } + + getEndpointPickingPolicy() { + return this.endpointPickingPolicy; + } + + getEdsServiceName() { + return this.edsServiceName; + } + + getLrsLoadReportingServerName() { + return this.lrsLoadReportingServerName; + } + + static createFromJson(obj: any): EdsLoadBalancingConfig { + if (!('cluster' in obj && typeof obj.cluster === 'string')) { + throw new Error('eds config must have a string field cluster'); + } + if (!('locality_picking_policy' in obj && Array.isArray(obj.locality_picking_policy))) { + throw new Error('eds config must have a locality_picking_policy array'); + } + if (!('endpoint_picking_policy' in obj && Array.isArray(obj.endpoint_picking_policy))) { + throw new Error('eds config must have an endpoint_picking_policy array'); + } + if ('eds_service_name' in obj && !(obj.eds_service_name === undefined || typeof obj.eds_service_name === 'string')) { + throw new Error('eds config eds_service_name field must be a string if provided'); + } + if ('lrs_load_reporting_server_name' in obj && (!obj.lrs_load_reporting_server_name === undefined || typeof obj.lrs_load_reporting_server_name === 'string')) { + throw new Error('eds config lrs_load_reporting_server_name must be a string if provided'); + } + return new EdsLoadBalancingConfig(obj.cluster, obj.locality_picking_policy.map(validateLoadBalancingConfig), obj.endpoint_picking_policy.map(validateLoadBalancingConfig), obj.eds_service_name, obj.lrs_load_reporting_server_name); + } +} + +/** + * This class load balances over a cluster by making an EDS request and then + * transforming the result into a configuration for another load balancing + * policy. + */ +export class EdsLoadBalancer implements LoadBalancer { + /** + * The child load balancer that will handle balancing the results of the EDS + * requests. + */ + private childBalancer: ChildLoadBalancerHandler; + private xdsClient: XdsClient | null = null; + private edsServiceName: string | null = null; + private watcher: Watcher; + /** + * Indicates whether the watcher has already been passed to this.xdsClient + * and is getting updates. + */ + private isWatcherActive = false; + + private lastestConfig: EdsLoadBalancingConfig | null = null; + private latestAttributes: { [key: string]: unknown } = {}; + private latestEdsUpdate: ClusterLoadAssignment__Output | null = null; + + /** + * The priority of each locality the last time we got an update. + */ + private localityPriorities: Map = new Map(); + /** + * The name we assigned to each priority number the last time we got an + * update. + */ + private priorityNames: string[] = []; + + private nextPriorityChildNumber = 0; + + private clusterDropStats: XdsClusterDropStats | null = null; + + constructor(private readonly channelControlHelper: ChannelControlHelper) { + this.childBalancer = new ChildLoadBalancerHandler({ + createSubchannel: (subchannelAddress, subchannelArgs) => + this.channelControlHelper.createSubchannel( + subchannelAddress, + subchannelArgs + ), + requestReresolution: () => + this.channelControlHelper.requestReresolution(), + updateState: (connectivityState, originalPicker) => { + if (this.latestEdsUpdate === null) { + return; + } + const edsPicker: Picker = { + pick: (pickArgs) => { + const dropCategory = this.checkForDrop(); + /* If we drop the call, it ends with an UNAVAILABLE status. + * Otherwise, delegate picking the subchannel to the child + * balancer. */ + if (dropCategory === null) { + return originalPicker.pick(pickArgs); + } else { + this.clusterDropStats?.addCallDropped(dropCategory); + return { + pickResultType: PickResultType.DROP, + status: { + code: Status.UNAVAILABLE, + details: `Call dropped by load balancing policy. Category: ${dropCategory}`, + metadata: new Metadata(), + }, + subchannel: null, + extraFilterFactory: null, + onCallStarted: null, + }; + } + }, + }; + this.channelControlHelper.updateState(connectivityState, edsPicker); + }, + }); + this.watcher = { + onValidUpdate: (update) => { + trace('Received EDS update for ' + this.edsServiceName + ': ' + JSON.stringify(update)); + this.latestEdsUpdate = update; + this.updateChild(); + }, + onResourceDoesNotExist: () => { + this.isWatcherActive = false; + this.channelControlHelper.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker({code: Status.UNAVAILABLE, details: 'EDS resource does not exist', metadata: new Metadata()})); + this.childBalancer.destroy(); + }, + onTransientError: (status) => { + if (this.latestEdsUpdate === null) { + channelControlHelper.updateState( + ConnectivityState.TRANSIENT_FAILURE, + new UnavailablePicker({ + code: Status.UNAVAILABLE, + details: `xDS request failed with error ${status.details}`, + metadata: new Metadata(), + }) + ); + } + }, + }; + } + + /** + * Check whether a single call should be dropped according to the current + * policy, based on randomly chosen numbers. Returns the drop category if + * the call should be dropped, and null otherwise. + */ + private checkForDrop(): string | null { + if (!this.latestEdsUpdate?.policy) { + return null; + } + /* The drop_overloads policy is a list of pairs of category names and + * probabilities. For each one, if the random number is within that + * probability range, we drop the call citing that category. Otherwise, the + * call proceeds as usual. */ + for (const dropOverload of this.latestEdsUpdate.policy.drop_overloads) { + if (!dropOverload.drop_percentage) { + continue; + } + let randNum: number; + switch (dropOverload.drop_percentage.denominator) { + case 'HUNDRED': + randNum = Math.random() * 100; + break; + case 'TEN_THOUSAND': + randNum = Math.random() * 10_000; + break; + case 'MILLION': + randNum = Math.random() * 1_000_000; + break; + default: + continue; + } + if (randNum < dropOverload.drop_percentage.numerator) { + return dropOverload.category; + } + } + return null; + } + + /** + * Should be called when this balancer gets a new config and when the + * XdsClient returns a new ClusterLoadAssignment. + */ + private updateChild() { + if (!(this.lastestConfig && this.latestEdsUpdate)) { + return; + } + /** + * Maps each priority number to the list of localities with that priority, + * and the list of addresses associated with each locality. + */ + const priorityList: { + locality: Locality__Output; + weight: number; + addresses: SubchannelAddress[]; + }[][] = []; + /** + * New replacement for this.localityPriorities, mapping locality names to + * priority values. The replacement occurrs at the end of this method. + */ + const newLocalityPriorities: Map = new Map< + string, + number + >(); + /* We are given a list of localities, each of which has a priority. This + * loop consolidates localities into buckets by priority, while also + * simplifying the data structure to make the later steps simpler */ + for (const endpoint of this.latestEdsUpdate.endpoints) { + if (!endpoint.load_balancing_weight) { + continue; + } + const addresses: SubchannelAddress[] = endpoint.lb_endpoints.filter(lbEndpoint => lbEndpoint.health_status === 'UNKNOWN' || lbEndpoint.health_status === 'HEALTHY').map( + (lbEndpoint) => { + /* The validator in the XdsClient class ensures that each endpoint has + * a socket_address with an IP address and a port_value. */ + const socketAddress = lbEndpoint.endpoint!.address!.socket_address!; + return { + host: socketAddress.address!, + port: socketAddress.port_value!, + }; + } + ); + if (addresses.length > 0) { + let localityArray = priorityList[endpoint.priority]; + if (localityArray === undefined) { + localityArray = []; + priorityList[endpoint.priority] = localityArray; + } + localityArray.push({ + locality: endpoint.locality!, + addresses: addresses, + weight: endpoint.load_balancing_weight.value, + }); + newLocalityPriorities.set( + localityToName(endpoint.locality!), + endpoint.priority + ); + } + } + + const newPriorityNames: string[] = []; + const addressList: LocalitySubchannelAddress[] = []; + const priorityChildren: Map = new Map< + string, + PriorityChild + >(); + /* The algorithm here is as follows: for each priority we are given, from + * high to low: + * - If the previous mapping had any of the same localities at the same or + * a lower priority, use the matching name from the highest such + * priority, unless the new mapping has already used that name. + * - Otherwise, construct a new name using this.nextPriorityChildNumber. + */ + for (const [priority, localityArray] of priorityList.entries()) { + // Skip priorities that have no localities with healthy endpoints + if (localityArray === undefined) { + continue; + } + /** + * Highest (smallest number) priority value that any of the localities in + * this locality array had a in the previous mapping. + */ + let highestOldPriority = Infinity; + for (const localityObj of localityArray) { + const oldPriority = this.localityPriorities.get( + localityToName(localityObj.locality) + ); + if ( + oldPriority !== undefined && + oldPriority >= priority && + oldPriority < highestOldPriority + ) { + highestOldPriority = oldPriority; + } + } + let newPriorityName: string; + if (highestOldPriority === Infinity) { + /* No existing priority at or below the same number as the priority we + * are looking at had any of the localities in this priority. So, we + * use a new name. */ + newPriorityName = `child${this.nextPriorityChildNumber++}`; + } else { + const newName = this.priorityNames[highestOldPriority]; + if (newPriorityNames.indexOf(newName) < 0) { + newPriorityName = newName; + } else { + newPriorityName = `child${this.nextPriorityChildNumber++}`; + } + } + newPriorityNames[priority] = newPriorityName; + + const childTargets: Map = new Map< + string, + WeightedTarget + >(); + for (const localityObj of localityArray) { + /* Use the endpoint picking policy from the config, default to + * round_robin. */ + const endpointPickingPolicy: LoadBalancingConfig[] = [ + ...this.lastestConfig.getEndpointPickingPolicy(), + validateLoadBalancingConfig({ round_robin: {} }), + ]; + let childPolicy: LoadBalancingConfig[]; + if (this.lastestConfig.getLrsLoadReportingServerName()) { + childPolicy = [new LrsLoadBalancingConfig(this.lastestConfig.getCluster(), this.lastestConfig.getEdsServiceName() ?? '', this.lastestConfig.getLrsLoadReportingServerName()!, localityObj.locality, endpointPickingPolicy)]; + } else { + childPolicy = endpointPickingPolicy; + } + childTargets.set(localityToName(localityObj.locality), { + weight: localityObj.weight, + child_policy: childPolicy, + }); + for (const address of localityObj.addresses) { + addressList.push({ + localityPath: [ + newPriorityName, + localityToName(localityObj.locality), + ], + ...address, + }); + } + } + + priorityChildren.set(newPriorityName, { + config: [ + new WeightedTargetLoadBalancingConfig(childTargets), + ], + }); + } + /* Contract the priority names array if it is sparse. This config only + * cares about the order of priorities, not their specific numbers */ + const childConfig: PriorityLoadBalancingConfig = new PriorityLoadBalancingConfig(priorityChildren, newPriorityNames.filter((value) => value !== undefined)); + trace('Child update addresses: ' + addressList.map(address => '(' + subchannelAddressToString(address) + ' path=' + address.localityPath + ')')); + trace('Child update priority config: ' + JSON.stringify(childConfig.toJsonObject(), undefined, 2)); + this.childBalancer.updateAddressList( + addressList, + childConfig, + this.latestAttributes + ); + + this.localityPriorities = newLocalityPriorities; + this.priorityNames = newPriorityNames; + } + + updateAddressList( + addressList: SubchannelAddress[], + lbConfig: LoadBalancingConfig, + attributes: { [key: string]: unknown } + ): void { + if (!(lbConfig instanceof EdsLoadBalancingConfig)) { + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2)); + return; + } + if (!(attributes.xdsClient instanceof XdsClient)) { + trace('Discarding address list update missing xdsClient attribute'); + return; + } + trace('Received update with config: ' + JSON.stringify(lbConfig, undefined, 2)); + this.lastestConfig = lbConfig; + this.latestAttributes = attributes; + this.xdsClient = attributes.xdsClient; + const newEdsServiceName = lbConfig.getEdsServiceName() ?? lbConfig.getCluster(); + + /* If the name is changing, disable the old watcher before adding the new + * one */ + if (this.isWatcherActive && this.edsServiceName !== newEdsServiceName) { + trace('Removing old endpoint watcher for edsServiceName ' + this.edsServiceName) + this.xdsClient.removeEndpointWatcher(this.edsServiceName!, this.watcher); + /* Setting isWatcherActive to false here lets us have one code path for + * calling addEndpointWatcher */ + this.isWatcherActive = false; + /* If we have a new name, the latestEdsUpdate does not correspond to + * the new config, so it is no longer valid */ + this.latestEdsUpdate = null; + } + + this.edsServiceName = newEdsServiceName; + + if (!this.isWatcherActive) { + trace('Adding new endpoint watcher for edsServiceName ' + this.edsServiceName); + this.xdsClient.addEndpointWatcher(this.edsServiceName, this.watcher); + this.isWatcherActive = true; + } + + if (lbConfig.getLrsLoadReportingServerName()) { + this.clusterDropStats = this.xdsClient.addClusterDropStats( + lbConfig.getLrsLoadReportingServerName()!, + lbConfig.getCluster(), + lbConfig.getEdsServiceName() ?? '' + ); + } + + /* If updateAddressList is called after receiving an update and the update + * is still valid, we want to update the child config with the information + * in the new EdsLoadBalancingConfig. */ + this.updateChild(); + } + exitIdle(): void { + this.childBalancer.exitIdle(); + } + resetBackoff(): void { + this.childBalancer.resetBackoff(); + } + destroy(): void { + trace('Destroying load balancer with edsServiceName ' + this.edsServiceName); + if (this.edsServiceName) { + this.xdsClient?.removeEndpointWatcher(this.edsServiceName, this.watcher); + } + this.childBalancer.destroy(); + } + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup() { + registerLoadBalancerType(TYPE_NAME, EdsLoadBalancer, EdsLoadBalancingConfig); +} diff --git a/packages/grpc-js-xds/src/load-balancer-lrs.ts b/packages/grpc-js-xds/src/load-balancer-lrs.ts new file mode 100644 index 00000000..b6fa6809 --- /dev/null +++ b/packages/grpc-js-xds/src/load-balancer-lrs.ts @@ -0,0 +1,242 @@ +/* + * Copyright 2020 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. + * + */ + +import { connectivityState as ConnectivityState, StatusObject, status as Status, experimental } from '@grpc/grpc-js'; +import { type } from 'os'; +import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; +import { XdsClusterLocalityStats, XdsClient } from './xds-client'; +import LoadBalancer = experimental.LoadBalancer; +import ChannelControlHelper = experimental.ChannelControlHelper; +import registerLoadBalancerType = experimental.registerLoadBalancerType; +import getFirstUsableConfig = experimental.getFirstUsableConfig; +import SubchannelAddress = experimental.SubchannelAddress; +import LoadBalancingConfig = experimental.LoadBalancingConfig; +import ChildLoadBalancerHandler = experimental.ChildLoadBalancerHandler; +import Picker = experimental.Picker; +import PickArgs = experimental.PickArgs; +import PickResultType = experimental.PickResultType; +import PickResult = experimental.PickResult; +import Filter = experimental.Filter; +import BaseFilter = experimental.BaseFilter; +import FilterFactory = experimental.FilterFactory; +import FilterStackFactory = experimental.FilterStackFactory; +import Call = experimental.CallStream; +import validateLoadBalancingConfig = experimental.validateLoadBalancingConfig + +const TYPE_NAME = 'lrs'; + +export class LrsLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + toJsonObject(): object { + return { + [TYPE_NAME]: { + cluster_name: this.clusterName, + eds_service_name: this.edsServiceName, + lrs_load_reporting_server_name: this.lrsLoadReportingServerName, + locality: this.locality, + child_policy: this.childPolicy.map(policy => policy.toJsonObject()) + } + } + } + + constructor(private clusterName: string, private edsServiceName: string, private lrsLoadReportingServerName: string, private locality: Locality__Output, private childPolicy: LoadBalancingConfig[]) {} + + getClusterName() { + return this.clusterName; + } + + getEdsServiceName() { + return this.edsServiceName; + } + + getLrsLoadReportingServerName() { + return this.lrsLoadReportingServerName; + } + + getLocality() { + return this.locality; + } + + getChildPolicy() { + return this.childPolicy; + } + + static createFromJson(obj: any): LrsLoadBalancingConfig { + if (!('cluster_name' in obj && typeof obj.cluster_name === 'string')) { + throw new Error('lrs config must have a string field cluster_name'); + } + if (!('eds_service_name' in obj && typeof obj.eds_service_name === 'string')) { + throw new Error('lrs config must have a string field eds_service_name'); + } + if (!('lrs_load_reporting_server_name' in obj && typeof obj.lrs_load_reporting_server_name === 'string')) { + throw new Error('lrs config must have a string field lrs_load_reporting_server_name'); + } + if (!('locality' in obj && obj.locality !== null && typeof obj.locality === 'object')) { + throw new Error('lrs config must have an object field locality'); + } + if ('region' in obj.locality && typeof obj.locality.region !== 'string') { + throw new Error('lrs config locality.region field must be a string if provided'); + } + if ('zone' in obj.locality && typeof obj.locality.zone !== 'string') { + throw new Error('lrs config locality.zone field must be a string if provided'); + } + if ('sub_zone' in obj.locality && typeof obj.locality.sub_zone !== 'string') { + throw new Error('lrs config locality.sub_zone field must be a string if provided'); + } + if (!('child_policy' in obj && Array.isArray(obj.child_policy))) { + throw new Error('lrs config must have a child_policy array'); + } + return new LrsLoadBalancingConfig(obj.cluster_name, obj.eds_service_name, obj.lrs_load_reporting_server_name, { + region: obj.locality.region ?? '', + zone: obj.locality.zone ?? '', + sub_zone: obj.locality.sub_zone ?? '' + }, obj.child_policy.map(validateLoadBalancingConfig)); + } +} + +/** + * Filter class that reports when the call ends. + */ +class CallEndTrackingFilter extends BaseFilter implements Filter { + constructor(private localityStatsReporter: XdsClusterLocalityStats) { + super(); + } + + receiveTrailers(status: StatusObject) { + this.localityStatsReporter.addCallFinished(status.code !== Status.OK); + return status; + } +} + +class CallEndTrackingFilterFactory + implements FilterFactory { + constructor(private localityStatsReporter: XdsClusterLocalityStats) {} + + createFilter(callStream: Call): CallEndTrackingFilter { + return new CallEndTrackingFilter(this.localityStatsReporter); + } +} + +/** + * Picker that delegates picking to another picker, and reports when calls + * created using those picks start and end. + */ +class LoadReportingPicker implements Picker { + constructor( + private wrappedPicker: Picker, + private localityStatsReporter: XdsClusterLocalityStats + ) {} + + pick(pickArgs: PickArgs): PickResult { + const wrappedPick = this.wrappedPicker.pick(pickArgs); + if (wrappedPick.pickResultType === PickResultType.COMPLETE) { + const trackingFilterFactory = new CallEndTrackingFilterFactory( + this.localityStatsReporter + ); + /* In the unlikely event that the wrappedPick already has an + * extraFilterFactory, preserve it in a FilterStackFactory. */ + const extraFilterFactory = wrappedPick.extraFilterFactory + ? new FilterStackFactory([ + wrappedPick.extraFilterFactory, + trackingFilterFactory, + ]) + : trackingFilterFactory; + return { + pickResultType: PickResultType.COMPLETE, + subchannel: wrappedPick.subchannel, + status: null, + onCallStarted: () => { + wrappedPick.onCallStarted?.(); + this.localityStatsReporter.addCallStarted(); + }, + extraFilterFactory: extraFilterFactory, + }; + } else { + return wrappedPick; + } + } +} + +/** + * "Load balancer" that delegates the actual load balancing logic to another + * LoadBalancer class and adds hooks to track when calls started using that + * LoadBalancer start and end, and uses the XdsClient to report that + * information back to the xDS server. + */ +export class LrsLoadBalancer implements LoadBalancer { + private childBalancer: ChildLoadBalancerHandler; + private localityStatsReporter: XdsClusterLocalityStats | null = null; + + constructor(private channelControlHelper: ChannelControlHelper) { + this.childBalancer = new ChildLoadBalancerHandler({ + createSubchannel: (subchannelAddress, subchannelArgs) => + channelControlHelper.createSubchannel( + subchannelAddress, + subchannelArgs + ), + requestReresolution: () => channelControlHelper.requestReresolution(), + updateState: (connectivityState: ConnectivityState, picker: Picker) => { + if (this.localityStatsReporter !== null) { + picker = new LoadReportingPicker(picker, this.localityStatsReporter); + } + channelControlHelper.updateState(connectivityState, picker); + }, + }); + } + + updateAddressList( + addressList: SubchannelAddress[], + lbConfig: LoadBalancingConfig, + attributes: { [key: string]: unknown } + ): void { + if (!(lbConfig instanceof LrsLoadBalancingConfig)) { + return; + } + if (!(attributes.xdsClient instanceof XdsClient)) { + return; + } + this.localityStatsReporter = attributes.xdsClient.addClusterLocalityStats( + lbConfig.getLrsLoadReportingServerName(), + lbConfig.getClusterName(), + lbConfig.getEdsServiceName(), + lbConfig.getLocality() + ); + const childPolicy: LoadBalancingConfig = getFirstUsableConfig( + lbConfig.getChildPolicy(), + true + ); + this.childBalancer.updateAddressList(addressList, childPolicy, attributes); + } + exitIdle(): void { + this.childBalancer.exitIdle(); + } + resetBackoff(): void { + this.childBalancer.resetBackoff(); + } + destroy(): void { + this.childBalancer.destroy(); + } + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup() { + registerLoadBalancerType(TYPE_NAME, LrsLoadBalancer, LrsLoadBalancingConfig); +} diff --git a/packages/grpc-js/src/load-balancer-priority.ts b/packages/grpc-js-xds/src/load-balancer-priority.ts similarity index 78% rename from packages/grpc-js/src/load-balancer-priority.ts rename to packages/grpc-js-xds/src/load-balancer-priority.ts index d3070715..872ed7d1 100644 --- a/packages/grpc-js/src/load-balancer-priority.ts +++ b/packages/grpc-js-xds/src/load-balancer-priority.ts @@ -15,23 +15,25 @@ * */ -import { - LoadBalancer, - ChannelControlHelper, - getFirstUsableConfig, - registerLoadBalancerType, -} from './load-balancer'; -import { SubchannelAddress } from './subchannel'; -import { - LoadBalancingConfig, - isPriorityLoadBalancingConfig, -} from './load-balancing-config'; -import { ConnectivityState } from './channel'; -import { Picker, QueuePicker, UnavailablePicker } from './picker'; -import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; -import { ChannelOptions } from './channel-options'; -import { Status } from './constants'; -import { Metadata } from './metadata'; +import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity as LogVerbosity, experimental, ChannelOptions } from '@grpc/grpc-js'; +import validateLoadBalancingConfig = experimental.validateLoadBalancingConfig; +import LoadBalancer = experimental.LoadBalancer; +import ChannelControlHelper = experimental.ChannelControlHelper; +import getFirstUsableConfig = experimental.getFirstUsableConfig; +import registerLoadBalancerType = experimental.registerLoadBalancerType; +import SubchannelAddress = experimental.SubchannelAddress; +import subchannelAddressToString = experimental.subchannelAddressToString; +import LoadBalancingConfig = experimental.LoadBalancingConfig; +import Picker = experimental.Picker; +import QueuePicker = experimental.QueuePicker; +import UnavailablePicker = experimental.UnavailablePicker; +import ChildLoadBalancerHandler = experimental.ChildLoadBalancerHandler; + +const TRACER_NAME = 'priority'; + +function trace(text: string): void { + experimental.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'priority'; @@ -48,6 +50,61 @@ export function isLocalitySubchannelAddress( return Array.isArray((address as LocalitySubchannelAddress).localityPath); } +export interface PriorityChild { + config: LoadBalancingConfig[]; +} + +export class PriorityLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + toJsonObject(): object { + const childrenField: {[key: string]: object} = {} + for (const [childName, childValue] of this.children.entries()) { + childrenField[childName] = { + config: childValue.config.map(value => value.toJsonObject()) + }; + } + return { + [TYPE_NAME]: { + children: childrenField, + priorities: this.priorities + } + } + } + + constructor(private children: Map, private priorities: string[]) { + } + + getChildren() { + return this.children; + } + + getPriorities() { + return this.priorities; + } + + static createFromJson(obj: any): PriorityLoadBalancingConfig { + if (!('children' in obj && obj.children !== null && typeof obj.children === 'object')) { + throw new Error('Priority config must have a children map'); + } + if (!('priorities' in obj && Array.isArray(obj.priorities) && (obj.priorities as any[]).every(value => typeof value === 'string'))) { + throw new Error('Priority config must have a priorities list'); + } + const childrenMap: Map = new Map(); + for (const childName of obj.children) { + const childObj = obj.children[childName] + if (!('config' in childObj && Array.isArray(childObj.config))) { + throw new Error(`Priority child ${childName} must have a config list`); + } + childrenMap.set(childName, { + config: childObj.config.map(validateLoadBalancingConfig) + }); + } + return new PriorityLoadBalancingConfig(childrenMap, obj.priorities); + } +} + interface PriorityChildBalancer { updateAddressList( addressList: SubchannelAddress[], @@ -103,6 +160,7 @@ export class PriorityLoadBalancer implements LoadBalancer { } private updateState(connectivityState: ConnectivityState, picker: Picker) { + trace('Child ' + this.name + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[connectivityState]); this.connectivityState = connectivityState; this.picker = picker; this.parent.onChildStateChange(this); @@ -110,7 +168,9 @@ export class PriorityLoadBalancer implements LoadBalancer { private startFailoverTimer() { if (this.failoverTimer === null) { + trace('Starting failover timer for child ' + this.name); this.failoverTimer = setTimeout(() => { + trace('Failover timer triggered for child ' + this.name); this.failoverTimer = null; this.updateState( ConnectivityState.TRANSIENT_FAILURE, @@ -222,6 +282,10 @@ export class PriorityLoadBalancer implements LoadBalancer { constructor(private channelControlHelper: ChannelControlHelper) {} private updateState(state: ConnectivityState, picker: Picker) { + trace( + 'Transitioning to ' + + ConnectivityState[state] + ); /* If switching to IDLE, use a QueuePicker attached to this load balancer * so that when the picker calls exitIdle, that in turn calls exitIdle on * the PriorityChildImpl, which will start the failover timer. */ @@ -233,6 +297,7 @@ export class PriorityLoadBalancer implements LoadBalancer { private onChildStateChange(child: PriorityChildBalancer) { const childState = child.getConnectivityState(); + trace('Child ' + child.getName() + ' transitioning to ' + ConnectivityState[childState]); if (child === this.currentChildFromBeforeUpdate) { if ( childState === ConnectivityState.READY || @@ -295,6 +360,7 @@ export class PriorityLoadBalancer implements LoadBalancer { private selectPriority(priority: number) { this.currentPriority = priority; const chosenChild = this.children.get(this.priorities[priority])!; + chosenChild.cancelFailoverTimer(); this.updateState( chosenChild.getConnectivityState(), chosenChild.getPicker() @@ -367,11 +433,11 @@ export class PriorityLoadBalancer implements LoadBalancer { lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown } ): void { - if (!isPriorityLoadBalancingConfig(lbConfig)) { + if (!(lbConfig instanceof PriorityLoadBalancingConfig)) { // Reject a config of the wrong type + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2)); return; } - const priorityConfig = lbConfig.priority; /* For each address, the first element of its localityPath array determines * which child it belongs to. So we bucket those addresses by that first * element, and pass along the rest of the localityPath for that child @@ -409,13 +475,14 @@ export class PriorityLoadBalancer implements LoadBalancer { } this.latestAttributes = attributes; this.latestUpdates.clear(); - this.priorities = priorityConfig.priorities; + this.priorities = lbConfig.getPriorities(); /* Pair up the new child configs with the corresponding address lists, and * update all existing children with their new configs */ - for (const [childName, childConfig] of priorityConfig.children) { + for (const [childName, childConfig] of lbConfig.getChildren()) { const chosenChildConfig = getFirstUsableConfig(childConfig.config); if (chosenChildConfig !== null) { const childAddresses = childAddressMap.get(childName) ?? []; + trace('Assigning child ' + childName + ' address list ' + childAddresses.map(address => '(' + subchannelAddressToString(address) + ' path=' + address.localityPath + ')')) this.latestUpdates.set(childName, { subchannelAddress: childAddresses, lbConfig: chosenChildConfig, @@ -433,6 +500,7 @@ export class PriorityLoadBalancer implements LoadBalancer { // Deactivate all children that are no longer in the priority list for (const [childName, child] of this.children) { if (this.priorities.indexOf(childName) < 0) { + trace('Deactivating child ' + childName); child.deactivate(); } } @@ -463,5 +531,5 @@ export class PriorityLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, PriorityLoadBalancer); + registerLoadBalancerType(TYPE_NAME, PriorityLoadBalancer, PriorityLoadBalancingConfig); } diff --git a/packages/grpc-js/src/load-balancer-weighted-target.ts b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts similarity index 69% rename from packages/grpc-js/src/load-balancer-weighted-target.ts rename to packages/grpc-js-xds/src/load-balancer-weighted-target.ts index 04145914..44a6acf1 100644 --- a/packages/grpc-js/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts @@ -15,20 +15,88 @@ * */ -import { LoadBalancer, ChannelControlHelper, getFirstUsableConfig, registerLoadBalancerType } from "./load-balancer"; -import { SubchannelAddress } from "./subchannel"; -import { LoadBalancingConfig, WeightedTarget, isWeightedTargetLoadBalancingConfig } from "./load-balancing-config"; -import { Picker, PickResult, PickArgs, QueuePicker, UnavailablePicker } from "./picker"; -import { ConnectivityState } from "./channel"; -import { ChildLoadBalancerHandler } from "./load-balancer-child-handler"; -import { Status } from "./constants"; -import { Metadata } from "./metadata"; +import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity, experimental } from "@grpc/grpc-js"; import { isLocalitySubchannelAddress, LocalitySubchannelAddress } from "./load-balancer-priority"; +import LoadBalancingConfig = experimental.LoadBalancingConfig; +import LoadBalancer = experimental.LoadBalancer; +import ChannelControlHelper = experimental.ChannelControlHelper; +import getFirstUsableConfig = experimental.getFirstUsableConfig; +import registerLoadBalancerType = experimental.registerLoadBalancerType; +import ChildLoadBalancerHandler = experimental.ChildLoadBalancerHandler; +import Picker = experimental.Picker; +import PickResult = experimental.PickResult; +import PickArgs = experimental.PickArgs; +import QueuePicker = experimental.QueuePicker; +import UnavailablePicker = experimental.UnavailablePicker; +import SubchannelAddress = experimental.SubchannelAddress; +import subchannelAddressToString = experimental.subchannelAddressToString; +import validateLoadBalancingConfig = experimental.validateLoadBalancingConfig; + +const TRACER_NAME = 'weighted_target'; + +function trace(text: string): void { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'weighted_target'; const DEFAULT_RETENTION_INTERVAL_MS = 15 * 60 * 1000; + export interface WeightedTarget { + weight: number; + child_policy: LoadBalancingConfig[]; +} + +export class WeightedTargetLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + + constructor(private targets: Map) { + } + + getTargets() { + return this.targets; + } + + toJsonObject(): object { + const targetsField: {[key: string]: object} = {}; + for (const [targetName, targetValue] of this.targets.entries()) { + targetsField[targetName] = { + weight: targetValue.weight, + child_policy: targetValue.child_policy.map(policy => policy.toJsonObject()) + }; + } + return { + [TYPE_NAME]: { + targets: targetsField + } + } + } + + static createFromJson(obj: any): WeightedTargetLoadBalancingConfig { + const targetsMap: Map = new Map(); + if (!('targets' in obj && obj.targets !== null && typeof obj.targets === 'object')) { + throw new Error('Weighted target config must have a targets map'); + } + for (const key of obj.targets) { + const targetObj = obj.targets[key]; + if (!('weight' in targetObj && typeof targetObj.weight === 'number')) { + throw new Error(`Weighted target ${key} must have a numeric weight`); + } + if (!('child_policy' in targetObj && Array.isArray(targetObj.child_policy))) { + throw new Error(`Weighted target ${key} must have a child_policy array`); + } + const validatedTarget: WeightedTarget = { + weight: targetObj.weight, + child_policy: targetObj.child_policy.map(validateLoadBalancingConfig) + } + targetsMap.set(key, validatedTarget); + } + return new WeightedTargetLoadBalancingConfig(targetsMap); + } +} + /** * Represents a picker and a subinterval of a larger interval used for randomly * selecting an element of a list of these objects. @@ -116,6 +184,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { } private updateState(connectivityState: ConnectivityState, picker: Picker) { + trace('Target ' + this.name + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[connectivityState]); this.connectivityState = connectivityState; this.picker = picker; this.parent.updateState(); @@ -229,7 +298,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { picker = new WeightedTargetPicker(pickerList); break; case ConnectivityState.CONNECTING: - case ConnectivityState.READY: + case ConnectivityState.IDLE: picker = new QueuePicker(this); break; default: @@ -239,12 +308,17 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { metadata: new Metadata() }); } + trace( + 'Transitioning to ' + + ConnectivityState[connectivityState] + ); this.channelControlHelper.updateState(connectivityState, picker); } updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown; }): void { - if (!isWeightedTargetLoadBalancingConfig(lbConfig)) { + if (!(lbConfig instanceof WeightedTargetLoadBalancingConfig)) { // Reject a config of the wrong type + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2)); return; } @@ -252,7 +326,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { * which child it belongs to. So we bucket those addresses by that first * element, and pass along the rest of the localityPath for that child * to use. */ - const childAddressMap = new Map(); + const childAddressMap = new Map(); for (const address of addressList) { if (!isLocalitySubchannelAddress(address)) { // Reject address that cannot be associated with targets @@ -275,8 +349,8 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { childAddressList.push(childAddress); } - this.targetList = Array.from(lbConfig.weighted_target.targets.keys()); - for (const [targetName, targetConfig] of lbConfig.weighted_target.targets) { + this.targetList = Array.from(lbConfig.getTargets().keys()); + for (const [targetName, targetConfig] of lbConfig.getTargets()) { let target = this.targets.get(targetName); if (target === undefined) { target = new this.WeightedChildImpl(this, targetName); @@ -284,12 +358,15 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { } else { target.maybeReactivate(); } - target.updateAddressList(childAddressMap.get(targetName) ?? [], targetConfig, attributes); + const targetAddresses = childAddressMap.get(targetName) ?? []; + trace('Assigning target ' + targetName + ' address list ' + targetAddresses.map(address => '(' + subchannelAddressToString(address) + ' path=' + address.localityPath + ')')); + target.updateAddressList(targetAddresses, targetConfig, attributes); } // Deactivate targets that are not in the new config for (const [targetName, target] of this.targets) { if (this.targetList.indexOf(targetName) < 0) { + trace('Deactivating target ' + targetName); target.deactivate(); } } @@ -318,5 +395,5 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, WeightedTargetLoadBalancer); + registerLoadBalancerType(TYPE_NAME, WeightedTargetLoadBalancer, WeightedTargetLoadBalancingConfig); } \ No newline at end of file diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts new file mode 100644 index 00000000..814294c8 --- /dev/null +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -0,0 +1,92 @@ +/* + * 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. + */ + +import { XdsClient } from './xds-client'; +import { StatusObject, status, logVerbosity, Metadata, experimental, ChannelOptions } from '@grpc/grpc-js'; +import Resolver = experimental.Resolver; +import GrpcUri = experimental.GrpcUri; +import ResolverListener = experimental.ResolverListener; +import uriToString = experimental.uriToString; +import ServiceConfig = experimental.ServiceConfig; +import registerResolver = experimental.registerResolver; + +const TRACER_NAME = 'xds_resolver'; + +function trace(text: string): void { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); +} + +class XdsResolver implements Resolver { + private resolutionStarted = false; + private hasReportedSuccess = false; + + constructor( + private target: GrpcUri, + private listener: ResolverListener, + private channelOptions: ChannelOptions + ) {} + + private reportResolutionError() { + this.listener.onError({ + code: status.UNAVAILABLE, + details: `xDS name resolution failed for target ${uriToString( + this.target + )}`, + metadata: new Metadata(), + }); + } + + updateResolution(): void { + // Wait until updateResolution is called once to start the xDS requests + if (!this.resolutionStarted) { + this.resolutionStarted = true; + trace('Starting resolution for target ' + uriToString(this.target)); + const xdsClient = new XdsClient( + this.target.path, + { + onValidUpdate: (update: ServiceConfig) => { + trace('Resolved service config for target ' + uriToString(this.target) + ': ' + JSON.stringify(update)); + this.hasReportedSuccess = true; + this.listener.onSuccessfulResolution([], update, null, { + xdsClient: xdsClient, + }); + }, + onTransientError: (error: StatusObject) => { + /* A transient error only needs to bubble up as a failure if we have + * not already provided a ServiceConfig for the upper layer to use */ + if (!this.hasReportedSuccess) { + trace('Resolution error for target ' + uriToString(this.target) + ' due to xDS client transient error ' + error.details); + this.reportResolutionError(); + } + }, + onResourceDoesNotExist: () => { + trace('Resolution error for target ' + uriToString(this.target) + ': resource does not exist'); + this.reportResolutionError(); + }, + }, + this.channelOptions + ); + } + } + + static getDefaultAuthority(target: GrpcUri) { + return target.path; + } +} + +export function setup() { + registerResolver('xds', XdsResolver); +} diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js-xds/src/xds-bootstrap.ts similarity index 95% rename from packages/grpc-js/src/xds-bootstrap.ts rename to packages/grpc-js-xds/src/xds-bootstrap.ts index b8e446b2..00e13d09 100644 --- a/packages/grpc-js/src/xds-bootstrap.ts +++ b/packages/grpc-js-xds/src/xds-bootstrap.ts @@ -157,15 +157,6 @@ function validateNode(obj: any): Node { throw new Error(`node.id field: expected string, got ${typeof obj.id}`); } result.id = obj.id; - if (!('cluster' in obj)) { - throw new Error('cluster field missing in node element'); - } - if (typeof obj.cluster !== 'string') { - throw new Error( - `node.cluster field: expected string, got ${typeof obj.cluster}` - ); - } - result.cluster = obj.cluster; if (!('locality' in obj)) { throw new Error('locality field missing in node element'); } @@ -180,7 +171,7 @@ function validateNode(obj: any): Node { result.locality.region = obj.locality.region; } if ('zone' in obj.locality) { - if (typeof obj.locality.region !== 'string') { + if (typeof obj.locality.zone !== 'string') { throw new Error( `node.locality.zone field: expected string, got ${typeof obj.locality .zone}` @@ -197,6 +188,14 @@ function validateNode(obj: any): Node { } result.locality.sub_zone = obj.locality.sub_zone; } + if ('cluster' in obj) { + if (typeof obj.cluster !== 'string') { + throw new Error( + `node.cluster field: expected string, got ${typeof obj.cluster}` + ); + } + result.cluster = obj.cluster; + } if ('metadata' in obj) { result.metadata = getStructFromJson(obj.metadata); } diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts new file mode 100644 index 00000000..525db769 --- /dev/null +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -0,0 +1,1253 @@ +/* + * Copyright 2020 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. + * + */ + +import * as protoLoader from '@grpc/proto-loader'; +import { loadPackageDefinition, StatusObject, status, logVerbosity, Metadata, experimental, ChannelOptions, ClientDuplexStream, ServiceError, ChannelCredentials } from '@grpc/grpc-js'; +import * as adsTypes from './generated/ads'; +import * as lrsTypes from './generated/lrs'; +import { loadBootstrapInfo } from './xds-bootstrap'; +import { isIPv4, isIPv6 } from 'net'; +import { Node } from './generated/envoy/api/v2/core/Node'; +import { AggregatedDiscoveryServiceClient } from './generated/envoy/service/discovery/v2/AggregatedDiscoveryService'; +import { DiscoveryRequest } from './generated/envoy/api/v2/DiscoveryRequest'; +import { DiscoveryResponse__Output } from './generated/envoy/api/v2/DiscoveryResponse'; +import { + ClusterLoadAssignment__Output, + ClusterLoadAssignment, +} from './generated/envoy/api/v2/ClusterLoadAssignment'; +import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; +import { LoadReportingServiceClient } from './generated/envoy/service/load_stats/v2/LoadReportingService'; +import { LoadStatsRequest } from './generated/envoy/service/load_stats/v2/LoadStatsRequest'; +import { LoadStatsResponse__Output } from './generated/envoy/service/load_stats/v2/LoadStatsResponse'; +import { + Locality__Output, + Locality, +} from './generated/envoy/api/v2/core/Locality'; +import { + ClusterStats, + _envoy_api_v2_endpoint_ClusterStats_DroppedRequests, +} from './generated/envoy/api/v2/endpoint/ClusterStats'; +import { UpstreamLocalityStats } from './generated/envoy/api/v2/endpoint/UpstreamLocalityStats'; +import { Listener__Output } from './generated/envoy/api/v2/Listener'; +import { HttpConnectionManager__Output } from './generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager'; +import { RouteConfiguration__Output } from './generated/envoy/api/v2/RouteConfiguration'; +import { Any__Output } from './generated/google/protobuf/Any'; +import BackoffTimeout = experimental.BackoffTimeout; +import ServiceConfig = experimental.ServiceConfig; +import createGoogleDefaultCredentials = experimental.createGoogleDefaultCredentials; +import { CdsLoadBalancingConfig } from './load-balancer-cds'; + +const TRACER_NAME = 'xds_client'; + +function trace(text: string): void { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); +} + +const clientVersion = require('../../package.json').version; + +const EDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; +const CDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Cluster'; +const LDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Listener'; +const RDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.RouteConfiguration'; + +type EdsTypeUrl = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; +type CdsTypeUrl = 'type.googleapis.com/envoy.api.v2.Cluster'; +type LdsTypeUrl = 'type.googleapis.com/envoy.api.v2.Listener'; +type RdsTypeUrl = 'type.googleapis.com/envoy.api.v2.RouteConfiguration'; + +type AdsTypeUrl = EdsTypeUrl | CdsTypeUrl | RdsTypeUrl | LdsTypeUrl; + +const HTTP_CONNECTION_MANGER_TYPE_URL = + 'type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager'; + +let loadedProtos: Promise< + adsTypes.ProtoGrpcType & lrsTypes.ProtoGrpcType +> | null = null; + +function loadAdsProtos(): Promise< + adsTypes.ProtoGrpcType & lrsTypes.ProtoGrpcType +> { + if (loadedProtos !== null) { + return loadedProtos; + } + loadedProtos = protoLoader + .load( + [ + 'envoy/service/discovery/v2/ads.proto', + 'envoy/service/load_stats/v2/lrs.proto', + 'envoy/api/v2/listener.proto', + 'envoy/api/v2/route.proto', + 'envoy/api/v2/cluster.proto', + 'envoy/api/v2/endpoint.proto', + 'envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto', + ], + { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + json: true, + includeDirs: [ + // Paths are relative to src/build + __dirname + '/../../deps/envoy-api/', + __dirname + '/../../deps/udpa/', + __dirname + '/../../deps/googleapis/', + __dirname + '/../../deps/protoc-gen-validate/', + ], + } + ) + .then( + (packageDefinition) => + (loadPackageDefinition( + packageDefinition + ) as unknown) as adsTypes.ProtoGrpcType & lrsTypes.ProtoGrpcType + ); + return loadedProtos; +} + +function localityEqual( + loc1: Locality__Output, + loc2: Locality__Output +): boolean { + return ( + loc1.region === loc2.region && + loc1.zone === loc2.zone && + loc1.sub_zone === loc2.sub_zone + ); +} + +export interface Watcher { + onValidUpdate(update: UpdateType): void; + onTransientError(error: StatusObject): void; + onResourceDoesNotExist(): void; +} + +export interface XdsClusterDropStats { + addCallDropped(category: string): void; +} + +export interface XdsClusterLocalityStats { + addCallStarted(): void; + addCallFinished(fail: boolean): void; +} + +interface ClusterLocalityStats { + locality: Locality__Output; + callsStarted: number; + callsSucceeded: number; + callsFailed: number; + callsInProgress: number; +} + +interface ClusterLoadReport { + callsDropped: Map; + localityStats: ClusterLocalityStats[]; + intervalStart: [number, number]; +} + +class ClusterLoadReportMap { + private statsMap: { + clusterName: string; + edsServiceName: string; + stats: ClusterLoadReport; + }[] = []; + + get( + clusterName: string, + edsServiceName: string + ): ClusterLoadReport | undefined { + for (const statsObj of this.statsMap) { + if ( + statsObj.clusterName === clusterName && + statsObj.edsServiceName === edsServiceName + ) { + return statsObj.stats; + } + } + return undefined; + } + + getOrCreate(clusterName: string, edsServiceName: string): ClusterLoadReport { + for (const statsObj of this.statsMap) { + if ( + statsObj.clusterName === clusterName && + statsObj.edsServiceName === edsServiceName + ) { + return statsObj.stats; + } + } + const newStats: ClusterLoadReport = { + callsDropped: new Map(), + localityStats: [], + intervalStart: process.hrtime(), + }; + this.statsMap.push({ + clusterName, + edsServiceName, + stats: newStats, + }); + return newStats; + } + + *entries(): IterableIterator< + [{ clusterName: string; edsServiceName: string }, ClusterLoadReport] + > { + for (const statsEntry of this.statsMap) { + yield [ + { + clusterName: statsEntry.clusterName, + edsServiceName: statsEntry.edsServiceName, + }, + statsEntry.stats, + ]; + } + } +} + +interface XdsStreamState { + versionInfo: string; + nonce: string; + getResourceNames(): string[]; + /** + * Returns a string containing the error details if the message should be nacked, + * or null if it should be acked. + * @param responses + */ + handleResponses(responses: ResponseType[]): string | null; + + reportStreamError(status: StatusObject): void; +} + +class EdsState implements XdsStreamState { + public versionInfo = ''; + public nonce = ''; + + private watchers: Map< + string, + Watcher[] + > = new Map[]>(); + + private latestResponses: ClusterLoadAssignment__Output[] = []; + + constructor(private updateResourceNames: () => void) {} + + /** + * Add the watcher to the watcher list. Returns true if the list of resource + * names has changed, and false otherwise. + * @param edsServiceName + * @param watcher + */ + addWatcher( + edsServiceName: string, + watcher: Watcher + ): void { + let watchersEntry = this.watchers.get(edsServiceName); + let addedServiceName = false; + if (watchersEntry === undefined) { + addedServiceName = true; + watchersEntry = []; + this.watchers.set(edsServiceName, watchersEntry); + } + trace('Adding EDS watcher (' + watchersEntry.length + ' ->' + (watchersEntry.length + 1) + ') for edsServiceName ' + edsServiceName); + watchersEntry.push(watcher); + + /* If we have already received an update for the requested edsServiceName, + * immediately pass that update along to the watcher */ + for (const message of this.latestResponses) { + if (message.cluster_name === edsServiceName) { + /* These updates normally occur asynchronously, so we ensure that + * the same happens here */ + process.nextTick(() => { + trace('Reporting existing EDS update for new watcher for edsServiceName ' + edsServiceName); + watcher.onValidUpdate(message); + }); + } + } + if (addedServiceName) { + this.updateResourceNames(); + } + } + + removeWatcher( + edsServiceName: string, + watcher: Watcher + ): void { + trace('Removing EDS watcher for edsServiceName ' + edsServiceName); + const watchersEntry = this.watchers.get(edsServiceName); + let removedServiceName = false; + if (watchersEntry !== undefined) { + const entryIndex = watchersEntry.indexOf(watcher); + if (entryIndex >= 0) { + trace('Removed EDS watcher (' + watchersEntry.length + ' -> ' + (watchersEntry.length - 1) + ') for edsServiceName ' + edsServiceName); + watchersEntry.splice(entryIndex, 1); + } + if (watchersEntry.length === 0) { + removedServiceName = true; + this.watchers.delete(edsServiceName); + } + } + if (removedServiceName) { + this.updateResourceNames(); + } + } + + getResourceNames(): string[] { + return Array.from(this.watchers.keys()); + } + + /** + * Validate the ClusterLoadAssignment object by these rules: + * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto + * @param message + */ + private validateResponse(message: ClusterLoadAssignment__Output) { + for (const endpoint of message.endpoints) { + for (const lb of endpoint.lb_endpoints) { + const socketAddress = lb.endpoint?.address?.socket_address; + if (!socketAddress) { + return false; + } + if (socketAddress.port_specifier !== 'port_value') { + return false; + } + if (!(isIPv4(socketAddress.address) || isIPv6(socketAddress.address))) { + return false; + } + } + } + return true; + } + + /** + * Given a list of edsServiceNames (which may actually be the cluster name), + * for each watcher watching a name not on the list, call that watcher's + * onResourceDoesNotExist method. + * @param allClusterNames + */ + handleMissingNames(allEdsServiceNames: Set) { + for (const [edsServiceName, watcherList] of this.watchers.entries()) { + if (!allEdsServiceNames.has(edsServiceName)) { + trace('Reporting EDS resource does not exist for edsServiceName ' + edsServiceName); + for (const watcher of watcherList) { + watcher.onResourceDoesNotExist(); + } + } + } + } + + handleResponses(responses: ClusterLoadAssignment__Output[]) { + for (const message of responses) { + if (!this.validateResponse(message)) { + trace('EDS validation failed for message ' + JSON.stringify(message)); + return 'EDS Error: ClusterLoadAssignment validation failed'; + } + } + this.latestResponses = responses; + const allClusterNames: Set = new Set(); + for (const message of responses) { + allClusterNames.add(message.cluster_name); + const watchers = this.watchers.get(message.cluster_name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); + } + } + trace('Received EDS updates for cluster names ' + Array.from(allClusterNames)); + this.handleMissingNames(allClusterNames); + return null; + } + + reportStreamError(status: StatusObject): void { + for (const watcherList of this.watchers.values()) { + for (const watcher of watcherList) { + watcher.onTransientError(status); + } + } + } +} + +class CdsState implements XdsStreamState { + versionInfo = ''; + nonce = ''; + + private watchers: Map[]> = new Map< + string, + Watcher[] + >(); + + private latestResponses: Cluster__Output[] = []; + + constructor( + private edsState: EdsState, + private updateResourceNames: () => void + ) {} + + /** + * Add the watcher to the watcher list. Returns true if the list of resource + * names has changed, and false otherwise. + * @param clusterName + * @param watcher + */ + addWatcher(clusterName: string, watcher: Watcher): void { + trace('Adding CDS watcher for clusterName ' + clusterName); + let watchersEntry = this.watchers.get(clusterName); + let addedServiceName = false; + if (watchersEntry === undefined) { + addedServiceName = true; + watchersEntry = []; + this.watchers.set(clusterName, watchersEntry); + } + watchersEntry.push(watcher); + + /* If we have already received an update for the requested edsServiceName, + * immediately pass that update along to the watcher */ + for (const message of this.latestResponses) { + if (message.name === clusterName) { + /* These updates normally occur asynchronously, so we ensure that + * the same happens here */ + process.nextTick(() => { + trace('Reporting existing CDS update for new watcher for clusterName ' + clusterName); + watcher.onValidUpdate(message); + }); + } + } + if (addedServiceName) { + this.updateResourceNames(); + } + } + + removeWatcher(clusterName: string, watcher: Watcher): void { + trace('Removing CDS watcher for clusterName ' + clusterName); + const watchersEntry = this.watchers.get(clusterName); + let removedServiceName = false; + if (watchersEntry !== undefined) { + const entryIndex = watchersEntry.indexOf(watcher); + if (entryIndex >= 0) { + watchersEntry.splice(entryIndex, 1); + } + if (watchersEntry.length === 0) { + removedServiceName = true; + this.watchers.delete(clusterName); + } + } + if (removedServiceName) { + this.updateResourceNames(); + } + } + + getResourceNames(): string[] { + return Array.from(this.watchers.keys()); + } + + private validateResponse(message: Cluster__Output): boolean { + if (message.type !== 'EDS') { + return false; + } + if (!message.eds_cluster_config?.eds_config?.ads) { + return false; + } + if (message.lb_policy !== 'ROUND_ROBIN') { + return false; + } + if (message.lrs_server) { + if (!message.lrs_server.self) { + return false; + } + } + return true; + } + + /** + * Given a list of clusterNames (which may actually be the cluster name), + * for each watcher watching a name not on the list, call that watcher's + * onResourceDoesNotExist method. + * @param allClusterNames + */ + private handleMissingNames(allClusterNames: Set) { + for (const [clusterName, watcherList] of this.watchers.entries()) { + if (!allClusterNames.has(clusterName)) { + trace('Reporting CDS resource does not exist for clusterName ' + clusterName); + for (const watcher of watcherList) { + watcher.onResourceDoesNotExist(); + } + } + } + } + + handleResponses(responses: Cluster__Output[]): string | null { + for (const message of responses) { + if (!this.validateResponse(message)) { + trace('CDS validation failed for message ' + JSON.stringify(message)); + return 'CDS Error: Cluster validation failed'; + } + } + this.latestResponses = responses; + const allEdsServiceNames: Set = new Set(); + const allClusterNames: Set = new Set(); + for (const message of responses) { + allClusterNames.add(message.name); + const edsServiceName = message.eds_cluster_config?.service_name ?? ''; + allEdsServiceNames.add( + edsServiceName === '' ? message.name : edsServiceName + ); + const watchers = this.watchers.get(message.name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); + } + } + trace('Received CDS updates for cluster names ' + Array.from(allClusterNames)); + this.handleMissingNames(allClusterNames); + this.edsState.handleMissingNames(allEdsServiceNames); + return null; + } + + reportStreamError(status: StatusObject): void { + for (const watcherList of this.watchers.values()) { + for (const watcher of watcherList) { + watcher.onTransientError(status); + } + } + } +} + +class RdsState implements XdsStreamState { + versionInfo = ''; + nonce = ''; + + private routeConfigName: string | null = null; + + constructor( + private targetName: string, + private watcher: Watcher, + private updateResouceNames: () => void + ) {} + + getResourceNames(): string[] { + return this.routeConfigName ? [this.routeConfigName] : []; + } + + handleSingleMessage(message: RouteConfiguration__Output) { + for (const virtualHost of message.virtual_hosts) { + if (virtualHost.domains.indexOf(this.targetName) >= 0) { + const route = virtualHost.routes[virtualHost.routes.length - 1]; + if (route.match?.prefix === '' && route.route?.cluster) { + trace('Reporting RDS update for host ' + this.targetName + ' with cluster ' + route.route.cluster); + this.watcher.onValidUpdate({ + methodConfig: [], + loadBalancingConfig: [ + new CdsLoadBalancingConfig(route.route.cluster) + ], + }); + return; + } else { + trace('Discarded matching route with prefix ' + route.match?.prefix + ' and cluster ' + route.route?.cluster); + } + } + } + trace('Reporting RDS resource does not exist from domain lists ' + message.virtual_hosts.map(virtualHost => virtualHost.domains)); + /* If none of the routes match the one we are looking for, bubble up an + * error. */ + this.watcher.onResourceDoesNotExist(); + } + + handleResponses(responses: RouteConfiguration__Output[]): string | null { + trace('Received RDS response with route config names ' + responses.map(message => message.name)); + if (this.routeConfigName !== null) { + for (const message of responses) { + if (message.name === this.routeConfigName) { + this.handleSingleMessage(message); + return null; + } + } + } + return null; + } + + setRouteConfigName(name: string | null) { + const oldName = this.routeConfigName; + this.routeConfigName = name; + if (name !== oldName) { + this.updateResouceNames(); + } + } + + reportStreamError(status: StatusObject): void { + this.watcher.onTransientError(status); + } +} + +class LdsState implements XdsStreamState { + versionInfo = ''; + nonce = ''; + + constructor(private targetName: string, private rdsState: RdsState) {} + + getResourceNames(): string[] { + return [this.targetName]; + } + + private validateResponse(message: Listener__Output): boolean { + if ( + !( + message.api_listener?.api_listener && + protoLoader.isAnyExtension(message.api_listener.api_listener) && + message.api_listener?.api_listener['@type'] === + HTTP_CONNECTION_MANGER_TYPE_URL + ) + ) { + return false; + } + const httpConnectionManager = message.api_listener + ?.api_listener as protoLoader.AnyExtension & + HttpConnectionManager__Output; + switch (httpConnectionManager.route_specifier) { + case 'rds': + return !!httpConnectionManager.rds?.config_source?.ads; + case 'route_config': + return true; + } + return false; + } + + handleResponses(responses: Listener__Output[]): string | null { + trace('Received LDS update with names ' + responses.map(message => message.name)); + for (const message of responses) { + if (message.name === this.targetName) { + if (this.validateResponse(message)) { + // The validation step ensures that this is correct + const httpConnectionManager = message.api_listener! + .api_listener as protoLoader.AnyExtension & + HttpConnectionManager__Output; + switch (httpConnectionManager.route_specifier) { + case 'rds': + trace('Received LDS update with RDS route config name ' + httpConnectionManager.rds!.route_config_name); + this.rdsState.setRouteConfigName( + httpConnectionManager.rds!.route_config_name + ); + break; + case 'route_config': + trace('Received LDS update with route configuration'); + this.rdsState.setRouteConfigName(null); + this.rdsState.handleSingleMessage( + httpConnectionManager.route_config! + ); + break; + default: + // The validation rules should prevent this + } + } else { + trace('LRS validation error for message ' + JSON.stringify(message)); + return 'LRS Error: Listener validation failed'; + } + } + } + return null; + } + + reportStreamError(status: StatusObject): void { + // Nothing to do here + } +} + +interface AdsState { + [EDS_TYPE_URL]: EdsState; + [CDS_TYPE_URL]: CdsState; + [RDS_TYPE_URL]: RdsState; + [LDS_TYPE_URL]: LdsState; +} + +/** + * Map type URLs to their corresponding message types + */ +type OutputType = T extends EdsTypeUrl + ? ClusterLoadAssignment__Output + : T extends CdsTypeUrl + ? Cluster__Output + : T extends RdsTypeUrl + ? RouteConfiguration__Output + : Listener__Output; + +function getResponseMessages( + typeUrl: T, + resources: Any__Output[] +): OutputType[] { + const result: OutputType[] = []; + for (const resource of resources) { + if (protoLoader.isAnyExtension(resource) && resource['@type'] === typeUrl) { + result.push(resource as protoLoader.AnyExtension & OutputType); + } else { + throw new Error( + `ADS Error: Invalid resource type ${ + protoLoader.isAnyExtension(resource) + ? resource['@type'] + : resource.type_url + }, expected ${typeUrl}` + ); + } + } + return result; +} + +export class XdsClient { + private adsNode: Node | null = null; + private adsClient: AggregatedDiscoveryServiceClient | null = null; + private adsCall: ClientDuplexStream< + DiscoveryRequest, + DiscoveryResponse__Output + > | null = null; + + private lrsNode: Node | null = null; + private lrsClient: LoadReportingServiceClient | null = null; + private lrsCall: ClientDuplexStream< + LoadStatsRequest, + LoadStatsResponse__Output + > | null = null; + private latestLrsSettings: LoadStatsResponse__Output | null = null; + + private clusterStatsMap: ClusterLoadReportMap = new ClusterLoadReportMap(); + private statsTimer: NodeJS.Timer; + + private hasShutdown = false; + + private adsState: AdsState; + + private adsBackoff: BackoffTimeout; + private lrsBackoff: BackoffTimeout; + + constructor( + targetName: string, + serviceConfigWatcher: Watcher, + channelOptions: ChannelOptions + ) { + const edsState = new EdsState(() => { + this.updateNames(EDS_TYPE_URL); + }); + const cdsState = new CdsState(edsState, () => { + this.updateNames(CDS_TYPE_URL); + }); + const rdsState = new RdsState(targetName, serviceConfigWatcher, () => { + this.updateNames(RDS_TYPE_URL); + }); + const ldsState = new LdsState(targetName, rdsState); + this.adsState = { + [EDS_TYPE_URL]: edsState, + [CDS_TYPE_URL]: cdsState, + [RDS_TYPE_URL]: rdsState, + [LDS_TYPE_URL]: ldsState, + }; + + const channelArgs = { ...channelOptions }; + const channelArgsToRemove = [ + /* The SSL target name override corresponds to the target, and this + * client has its own target */ + 'grpc.ssl_target_name_override', + /* The default authority also corresponds to the target */ + 'grpc.default_authority', + /* This client will have its own specific keepalive time setting */ + 'grpc.keepalive_time_ms', + /* The service config specifies the load balancing policy. This channel + * needs its own separate load balancing policy setting. In particular, + * recursively using an xDS load balancer for the xDS client would be + * bad */ + 'grpc.service_config', + ]; + for (const arg of channelArgsToRemove) { + delete channelArgs[arg]; + } + // 5 minutes + channelArgs['grpc.keepalive_time_ms'] = 5 * 60 * 1000; + + this.adsBackoff = new BackoffTimeout(() => { + this.maybeStartAdsStream(); + }); + this.lrsBackoff = new BackoffTimeout(() => { + this.maybeStartLrsStream(); + }) + + Promise.all([loadBootstrapInfo(), loadAdsProtos()]).then( + ([bootstrapInfo, protoDefinitions]) => { + if (this.hasShutdown) { + return; + } + const node: Node = { + ...bootstrapInfo.node, + build_version: `gRPC Node Pure JS ${clientVersion}`, + user_agent_name: 'gRPC Node Pure JS', + }; + this.adsNode = { + ...node, + client_features: ['envoy.lb.does_not_support_overprovisioning'], + }; + this.lrsNode = { + ...node, + client_features: ['envoy.lrs.supports_send_all_clusters'], + }; + const credentialsConfigs = bootstrapInfo.xdsServers[0].channelCreds; + let channelCreds: ChannelCredentials | null = null; + for (const config of credentialsConfigs) { + if (config.type === 'google_default') { + channelCreds = createGoogleDefaultCredentials(); + break; + } else if (config.type === 'insecure') { + channelCreds = ChannelCredentials.createInsecure(); + break; + } + } + if (channelCreds === null) { + trace('Failed to initialize xDS Client. No valid credentials types found.'); + // Bubble this error up to any listeners + this.reportStreamError({ + code: status.INTERNAL, + details: 'Failed to initialize xDS Client. No valid credentials types found.', + metadata: new Metadata(), + }); + return; + } + trace('Starting xDS client connected to server URI ' + bootstrapInfo.xdsServers[0].serverUri); + this.adsClient = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( + bootstrapInfo.xdsServers[0].serverUri, + channelCreds, + channelArgs + ); + this.maybeStartAdsStream(); + + this.lrsClient = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( + bootstrapInfo.xdsServers[0].serverUri, + channelCreds, + {channelOverride: this.adsClient.getChannel()} + ); + this.maybeStartLrsStream(); + }, + (error) => { + trace('Failed to initialize xDS Client. ' + error.message); + // Bubble this error up to any listeners + this.reportStreamError({ + code: status.INTERNAL, + details: `Failed to initialize xDS Client. ${error.message}`, + metadata: new Metadata(), + }); + } + ); + this.statsTimer = setInterval(() => {}, 0); + clearInterval(this.statsTimer); + } + + private handleAdsResponse(message: DiscoveryResponse__Output) { + let errorString: string | null; + /* The cases in this switch statement look redundant but separating them + * out like this is necessary for the typechecker to validate the types + * as narrowly as we need it to. */ + switch (message.type_url) { + case EDS_TYPE_URL: + errorString = this.adsState[message.type_url].handleResponses( + getResponseMessages(message.type_url, message.resources) + ); + break; + case CDS_TYPE_URL: + errorString = this.adsState[message.type_url].handleResponses( + getResponseMessages(message.type_url, message.resources) + ); + break; + case RDS_TYPE_URL: + errorString = this.adsState[message.type_url].handleResponses( + getResponseMessages(message.type_url, message.resources) + ); + break; + case LDS_TYPE_URL: + errorString = this.adsState[message.type_url].handleResponses( + getResponseMessages(message.type_url, message.resources) + ); + break; + default: + errorString = `Unknown type_url ${message.type_url}`; + } + if (errorString === null) { + trace('Acking message with type URL ' + message.type_url); + /* errorString can only be null in one of the first 4 cases, which + * implies that message.type_url is one of the 4 known type URLs, which + * means that this type assertion is valid. */ + const typeUrl = message.type_url as AdsTypeUrl; + this.adsState[typeUrl].nonce = message.nonce; + this.adsState[typeUrl].versionInfo = message.version_info; + this.ack(typeUrl); + } else { + trace('Nacking message with type URL ' + message.type_url + ': "' + errorString + '"'); + this.nack(message.type_url, errorString); + } + } + + /** + * Start the ADS stream if the client exists and there is not already an + * existing stream, and there + */ + private maybeStartAdsStream() { + if (this.adsClient === null) { + return; + } + if (this.adsCall !== null) { + return; + } + if (this.hasShutdown) { + return; + } + trace('Starting ADS stream'); + // Backoff relative to when we start the request + this.adsBackoff.runOnce(); + this.adsCall = this.adsClient.StreamAggregatedResources(); + this.adsCall.on('data', (message: DiscoveryResponse__Output) => { + this.handleAdsResponse(message); + }); + this.adsCall.on('error', (error: ServiceError) => { + trace( + 'ADS stream ended. code=' + error.code + ' details= ' + error.details + ); + this.adsCall = null; + this.reportStreamError(error); + /* If the backoff timer is no longer running, we do not need to wait any + * more to start the new call. */ + if (!this.adsBackoff.isRunning()) { + this.maybeStartAdsStream(); + } + }); + + const allTypeUrls: AdsTypeUrl[] = [ + EDS_TYPE_URL, + CDS_TYPE_URL, + RDS_TYPE_URL, + LDS_TYPE_URL, + ]; + for (const typeUrl of allTypeUrls) { + const state = this.adsState[typeUrl]; + if (state.getResourceNames().length > 0) { + this.updateNames(typeUrl); + } + } + } + + /** + * Acknowledge an update. This should be called after the local nonce and + * version info are updated so that it sends the post-update values. + */ + ack(typeUrl: AdsTypeUrl) { + /* An ack is the best indication of a successful interaction between the + * client and the server, so we can reset the backoff timer here. */ + this.adsBackoff.stop(); + this.adsBackoff.reset(); + + this.updateNames(typeUrl); + } + + /** + * Reject an update. This should be called without updating the local + * nonce and version info. + */ + private nack(typeUrl: string, message: string) { + let resourceNames: string[]; + let nonce: string; + let versionInfo: string; + switch (typeUrl) { + case EDS_TYPE_URL: + case CDS_TYPE_URL: + case RDS_TYPE_URL: + case LDS_TYPE_URL: + resourceNames = this.adsState[typeUrl].getResourceNames(); + nonce = this.adsState[typeUrl].nonce; + versionInfo = this.adsState[typeUrl].versionInfo; + break; + default: + resourceNames = []; + nonce = ''; + versionInfo = ''; + } + this.adsCall?.write({ + node: this.adsNode!, + type_url: typeUrl, + resource_names: resourceNames, + response_nonce: nonce, + version_info: versionInfo, + error_detail: { + message: message, + }, + }); + } + + private updateNames(typeUrl: AdsTypeUrl) { + trace('Sending update for type URL ' + typeUrl + ' with names ' + this.adsState[typeUrl].getResourceNames()); + this.adsCall?.write({ + node: this.adsNode!, + type_url: typeUrl, + resource_names: this.adsState[typeUrl].getResourceNames(), + response_nonce: this.adsState[typeUrl].nonce, + version_info: this.adsState[typeUrl].versionInfo, + }); + } + + private reportStreamError(status: StatusObject) { + this.adsState[EDS_TYPE_URL].reportStreamError(status); + this.adsState[CDS_TYPE_URL].reportStreamError(status); + this.adsState[RDS_TYPE_URL].reportStreamError(status); + this.adsState[LDS_TYPE_URL].reportStreamError(status); + } + + private maybeStartLrsStream() { + if (!this.lrsClient) { + return; + } + if (this.lrsCall) { + return; + } + if (this.hasShutdown) { + return; + } + + trace('Starting LRS stream'); + + this.lrsBackoff.runOnce(); + this.lrsCall = this.lrsClient.streamLoadStats(); + this.lrsCall.on('metadata', () => { + /* Once we get any response from the server, we assume that the stream is + * in a good state, so we can reset the backoff timer. */ + this.lrsBackoff.stop(); + this.lrsBackoff.reset(); + }); + this.lrsCall.on('data', (message: LoadStatsResponse__Output) => { + if ( + message.load_reporting_interval?.seconds !== + this.latestLrsSettings?.load_reporting_interval?.seconds || + message.load_reporting_interval?.nanos !== + this.latestLrsSettings?.load_reporting_interval?.nanos + ) { + /* Only reset the timer if the interval has changed or was not set + * before. */ + clearInterval(this.statsTimer); + /* Convert a google.protobuf.Duration to a number of milliseconds for + * use with setInterval. */ + const loadReportingIntervalMs = + Number.parseInt(message.load_reporting_interval!.seconds) * 1000 + + message.load_reporting_interval!.nanos / 1_000_000; + trace('Received LRS request with load reporting interval ' + loadReportingIntervalMs + ' ms'); + this.statsTimer = setInterval(() => { + this.sendStats(); + }, loadReportingIntervalMs); + } + this.latestLrsSettings = message; + }); + this.lrsCall.on('error', (error: ServiceError) => { + trace( + 'LRS stream ended. code=' + error.code + ' details= ' + error.details + ); + this.lrsCall = null; + this.latestLrsSettings = null; + clearInterval(this.statsTimer); + /* If the backoff timer is no longer running, we do not need to wait any + * more to start the new call. */ + if (!this.lrsBackoff.isRunning()) { + this.maybeStartLrsStream(); + } + }); + /* Send buffered stats information when starting LRS stream. If there is no + * buffered stats information, it will still send the node field. */ + this.sendStats(); + } + + private sendStats() { + if (!this.lrsCall) { + return; + } + trace('Sending LRS stats'); + const clusterStats: ClusterStats[] = []; + for (const [ + { clusterName, edsServiceName }, + stats, + ] of this.clusterStatsMap.entries()) { + if ( + this.latestLrsSettings!.send_all_clusters || + this.latestLrsSettings!.clusters.indexOf(clusterName) > 0 + ) { + const upstreamLocalityStats: UpstreamLocalityStats[] = []; + for (const localityStats of stats.localityStats) { + // Skip localities with 0 requests + if ( + localityStats.callsStarted > 0 || + localityStats.callsSucceeded > 0 || + localityStats.callsFailed > 0 + ) { + upstreamLocalityStats.push({ + locality: localityStats.locality, + total_issued_requests: localityStats.callsStarted, + total_successful_requests: localityStats.callsSucceeded, + total_error_requests: localityStats.callsFailed, + total_requests_in_progress: localityStats.callsInProgress, + }); + localityStats.callsStarted = 0; + localityStats.callsSucceeded = 0; + localityStats.callsFailed = 0; + } + } + const droppedRequests: _envoy_api_v2_endpoint_ClusterStats_DroppedRequests[] = []; + let totalDroppedRequests = 0; + for (const [category, count] of stats.callsDropped.entries()) { + if (count > 0) { + droppedRequests.push({ + category, + dropped_count: count, + }); + totalDroppedRequests += count; + } + } + // Clear out dropped call stats after sending them + stats.callsDropped.clear(); + const interval = process.hrtime(stats.intervalStart); + stats.intervalStart = process.hrtime(); + // Skip clusters with 0 requests + if (upstreamLocalityStats.length > 0 || totalDroppedRequests > 0) { + clusterStats.push({ + cluster_name: clusterName, + cluster_service_name: edsServiceName, + dropped_requests: droppedRequests, + total_dropped_requests: totalDroppedRequests, + upstream_locality_stats: upstreamLocalityStats, + load_report_interval: { + seconds: interval[0], + nanos: interval[1], + }, + }); + } + } + } + this.lrsCall.write({ + node: this.lrsNode!, + cluster_stats: clusterStats, + }); + } + + addEndpointWatcher( + edsServiceName: string, + watcher: Watcher + ) { + trace('Watcher added for endpoint ' + edsServiceName); + this.adsState[EDS_TYPE_URL].addWatcher(edsServiceName, watcher); + } + + removeEndpointWatcher( + edsServiceName: string, + watcher: Watcher + ) { + trace('Watcher removed for endpoint ' + edsServiceName); + this.adsState[EDS_TYPE_URL].removeWatcher(edsServiceName, watcher); + } + + addClusterWatcher(clusterName: string, watcher: Watcher) { + trace('Watcher added for cluster ' + clusterName); + this.adsState[CDS_TYPE_URL].addWatcher(clusterName, watcher); + } + + removeClusterWatcher(clusterName: string, watcher: Watcher) { + trace('Watcher removed for endpoint ' + clusterName); + this.adsState[CDS_TYPE_URL].removeWatcher(clusterName, watcher); + } + + /** + * + * @param lrsServer The target name of the server to send stats to. An empty + * string indicates that the default LRS client should be used. Currently + * only the empty string is supported here. + * @param clusterName + * @param edsServiceName + */ + addClusterDropStats( + lrsServer: string, + clusterName: string, + edsServiceName: string + ): XdsClusterDropStats { + if (lrsServer !== '') { + return { + addCallDropped: (category) => {}, + }; + } + const clusterStats = this.clusterStatsMap.getOrCreate( + clusterName, + edsServiceName + ); + return { + addCallDropped: (category) => { + const prevCount = clusterStats.callsDropped.get(category) ?? 0; + clusterStats.callsDropped.set(category, prevCount + 1); + }, + }; + } + + addClusterLocalityStats( + lrsServer: string, + clusterName: string, + edsServiceName: string, + locality: Locality__Output + ): XdsClusterLocalityStats { + if (lrsServer !== '') { + return { + addCallStarted: () => {}, + addCallFinished: (fail) => {}, + }; + } + const clusterStats = this.clusterStatsMap.getOrCreate( + clusterName, + edsServiceName + ); + let localityStats: ClusterLocalityStats | null = null; + for (const statsObj of clusterStats.localityStats) { + if (localityEqual(locality, statsObj.locality)) { + localityStats = statsObj; + break; + } + } + if (localityStats === null) { + localityStats = { + locality: locality, + callsInProgress: 0, + callsStarted: 0, + callsSucceeded: 0, + callsFailed: 0, + }; + clusterStats.localityStats.push(localityStats); + } + /* Help the compiler understand that this object is always non-null in the + * closure */ + const finalLocalityStats: ClusterLocalityStats = localityStats; + return { + addCallStarted: () => { + finalLocalityStats.callsStarted += 1; + finalLocalityStats.callsInProgress += 1; + }, + addCallFinished: (fail) => { + if (fail) { + finalLocalityStats.callsFailed += 1; + } else { + finalLocalityStats.callsSucceeded += 1; + } + finalLocalityStats.callsInProgress -= 1; + }, + }; + } + + shutdown(): void { + this.adsCall?.cancel(); + this.adsClient?.close(); + this.lrsCall?.cancel(); + this.lrsClient?.close(); + this.hasShutdown = true; + } +} diff --git a/packages/grpc-js-xds/test/test-register.ts b/packages/grpc-js-xds/test/test-register.ts new file mode 100644 index 00000000..e7a07927 --- /dev/null +++ b/packages/grpc-js-xds/test/test-register.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2020 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. + * + */ + +import * as assert from 'assert'; +import { register } from '../src'; + +/* This is just a basic test to confirm that the package builds and the setup + * code runs. */ +describe('register function', () => { + it('Should succeed without errors', () => { + assert.doesNotThrow(register); + }); +}); \ No newline at end of file diff --git a/packages/grpc-js-xds/tsconfig.json b/packages/grpc-js-xds/tsconfig.json new file mode 100644 index 00000000..c121a5f6 --- /dev/null +++ b/packages/grpc-js-xds/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "./node_modules/gts/tsconfig-google.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "build", + "target": "es2017", + "lib": ["es2017"], + "module": "commonjs", + "incremental": true + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts", + "interop/**/*.ts" + ] +} diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index 4d0cb548..4bb4da02 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -8,6 +8,10 @@ Node 12 is recommended. The exact set of compatible Node versions can be found i npm install @grpc/grpc-js ``` +## Documentation + +Documentation specifically for the `@grpc/grpc-js` package is currently not available. However, [documentation is available for the `grpc` package](https://grpc.github.io/grpc/node/grpc.html), and the two packages contain mostly the same interface. There are a few notable differences, however, and these differences are noted in the "Migrating from grpc" section below. + ## Features - Clients @@ -28,7 +32,7 @@ This library does not directly handle `.proto` files. To use `.proto` files with `@grpc/grpc-js` is almost a drop-in replacement for `grpc`, but you may need to make a few code changes to use it: - If you are currently loading `.proto` files using `grpc.load`, that function is not available in this library. You should instead load your `.proto` files using `@grpc/proto-loader` and load the resulting package definition objects into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. -- If you are currently loading packages generated by `grpc-tools`, you should instead generate your files using the `--generate_package_definitions` option in `grpc-tools`, then load the object exported by the generated file into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. +- If you are currently loading packages generated by `grpc-tools`, you should instead generate your files using the `generate_package_definition` option in `grpc-tools`, then load the object exported by the generated file into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. - If you have a server and you are using `Server#bind` to bind ports, you will need to use `Server#bindAsync` instead. ## Some Notes on API Guarantees @@ -38,3 +42,4 @@ The public API of this library follows semantic versioning, with some caveats: - Some methods are prefixed with an underscore. These methods are internal and should not be considered part of the public API. - The class `Call` is only exposed due to limitations of TypeScript. It should not be considered part of the public API. - In general, any API that is exposed by this library but is not exposed by the `grpc` library is likely an error and should not be considered part of the public API. +- The `grpc.experimental` namespace contains APIs that have not stabilized. Any API in that namespace may break in any minor version update. diff --git a/packages/grpc-js/log.txt b/packages/grpc-js/log.txt new file mode 100644 index 00000000..7a6bbc2c --- /dev/null +++ b/packages/grpc-js/log.txt @@ -0,0 +1,971 @@ +{ + O: [Getter/Setter], + outDir: [Getter/Setter], + 'out-dir': [Getter/Setter], + _: [ + 'envoy/service/discovery/v2/ads.proto', + 'envoy/api/v2/listener.proto', + 'envoy/api/v2/route.proto', + 'envoy/api/v2/cluster.proto', + 'envoy/api/v2/endpoint.proto' + ], + keepCase: true, + 'keep-case': true, + longs: [Function: String], + enums: [Function: String], + defaults: true, + oneofs: true, + json: true, + includeDirs: [ + 'deps/envoy-api/', + 'deps/udpa/', + 'node_modules/protobufjs/', + 'deps/googleapis/', + 'deps/protoc-gen-validate/' + ], + I: [ + 'deps/envoy-api/', + 'deps/udpa/', + 'node_modules/protobufjs/', + 'deps/googleapis/', + 'deps/protoc-gen-validate/' + ], + 'include-dirs': [ + 'deps/envoy-api/', + 'deps/udpa/', + 'node_modules/protobufjs/', + 'deps/googleapis/', + 'deps/protoc-gen-validate/' + ], + grpcLib: '../index', + 'grpc-lib': '../index', + '$0': 'node_modules/.bin/proto-loader-gen-types' +} +Processing envoy/service/discovery/v2/ads.proto +Writing src/generated//ads.d.ts +Writing src/generated//envoy/service/discovery/v2/AdsDummy.d.ts from file deps/envoy-api/envoy/service/discovery/v2/ads.proto +Writing src/generated//envoy/api/v2/DiscoveryRequest.d.ts from file deps/envoy-api/envoy/api/v2/discovery.proto +Writing src/generated//envoy/api/v2/DiscoveryResponse.d.ts from file deps/envoy-api/envoy/api/v2/discovery.proto +Writing src/generated//envoy/api/v2/DeltaDiscoveryRequest.d.ts from file deps/envoy-api/envoy/api/v2/discovery.proto +Writing src/generated//envoy/api/v2/DeltaDiscoveryResponse.d.ts from file deps/envoy-api/envoy/api/v2/discovery.proto +Writing src/generated//envoy/api/v2/Resource.d.ts from file deps/envoy-api/envoy/api/v2/discovery.proto +Writing src/generated//envoy/api/v2/core/RoutingPriority.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RequestMethod.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TrafficDirection.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Locality.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/BuildVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Extension.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Node.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Metadata.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeUInt32.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeDouble.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFeatureFlag.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValue.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValueOption.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderMap.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/DataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RemoteDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/AsyncDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TransportSocket.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFractionalPercent.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/ControlPlane.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Pipe.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress/Protocol.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/TcpKeepalive.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BindConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/Address.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/CidrRange.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BackoffStrategy.d.ts from file deps/envoy-api/envoy/api/v2/core/backoff.proto +Writing src/generated//envoy/api/v2/core/SocketOption.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/SocketOption/SocketState.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/HttpUri.d.ts from file deps/envoy-api/envoy/api/v2/core/http_uri.proto +Writing src/generated//envoy/type/Percent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent/DenominatorType.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/SemanticVersion.d.ts from file deps/envoy-api/envoy/type/semantic_version.proto +Writing src/generated//udpa/annotations/PackageVersionStatus.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//udpa/annotations/StatusAnnotation.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//udpa/annotations/MigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FieldMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FileMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//validate/FieldRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/FloatRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DoubleRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BoolRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/StringRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/KnownRegex.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BytesRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/EnumRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MessageRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/RepeatedRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MapRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/AnyRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DurationRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/TimestampRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//google/protobuf/Any.d.ts from file null +Writing src/generated//google/protobuf/Duration.d.ts from file null +Writing src/generated//google/protobuf/Struct.d.ts from file null +Writing src/generated//google/protobuf/Value.d.ts from file null +Writing src/generated//google/protobuf/NullValue.d.ts from file null +Writing src/generated//google/protobuf/ListValue.d.ts from file null +Writing src/generated//google/protobuf/DoubleValue.d.ts from file null +Writing src/generated//google/protobuf/FloatValue.d.ts from file null +Writing src/generated//google/protobuf/Int64Value.d.ts from file null +Writing src/generated//google/protobuf/UInt64Value.d.ts from file null +Writing src/generated//google/protobuf/Int32Value.d.ts from file null +Writing src/generated//google/protobuf/UInt32Value.d.ts from file null +Writing src/generated//google/protobuf/BoolValue.d.ts from file null +Writing src/generated//google/protobuf/StringValue.d.ts from file null +Writing src/generated//google/protobuf/BytesValue.d.ts from file null +Writing src/generated//google/protobuf/FileDescriptorSet.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ExtensionRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ReservedRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Type.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Label.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions/OptimizeMode.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MessageOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/CType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/JSType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption/NamePart.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo/Location.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo/Annotation.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/Timestamp.d.ts from file null +Writing src/generated//google/rpc/Status.d.ts from file deps/googleapis/google/rpc/status.proto +Processing envoy/api/v2/listener.proto +Writing src/generated//listener.d.ts +Writing src/generated//envoy/api/v2/Listener.d.ts from file deps/envoy-api/envoy/api/v2/listener.proto +Writing src/generated//envoy/api/v2/Listener/DrainType.d.ts from file deps/envoy-api/envoy/api/v2/listener.proto +Writing src/generated//envoy/api/v2/Listener/DeprecatedV1.d.ts from file deps/envoy-api/envoy/api/v2/listener.proto +Writing src/generated//envoy/api/v2/Listener/ConnectionBalanceConfig.d.ts from file deps/envoy-api/envoy/api/v2/listener.proto +Writing src/generated//envoy/api/v2/Listener/ConnectionBalanceConfig/ExactBalance.d.ts from file deps/envoy-api/envoy/api/v2/listener.proto +Writing src/generated//envoy/api/v2/listener/Filter.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/FilterChainMatch.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/FilterChainMatch/ConnectionSourceType.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/FilterChain.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/ListenerFilterChainMatchPredicate.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/ListenerFilterChainMatchPredicate/MatchSet.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/ListenerFilter.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/UdpListenerConfig.d.ts from file deps/envoy-api/envoy/api/v2/listener/udp_listener_config.proto +Writing src/generated//envoy/api/v2/listener/ActiveRawUdpListenerConfig.d.ts from file deps/envoy-api/envoy/api/v2/listener/udp_listener_config.proto +Writing src/generated//envoy/api/v2/core/SocketOption.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/SocketOption/SocketState.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/RoutingPriority.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RequestMethod.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TrafficDirection.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Locality.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/BuildVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Extension.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Node.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Metadata.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeUInt32.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeDouble.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFeatureFlag.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValue.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValueOption.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderMap.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/DataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RemoteDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/AsyncDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TransportSocket.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFractionalPercent.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/ControlPlane.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Pipe.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress/Protocol.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/TcpKeepalive.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BindConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/Address.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/CidrRange.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BackoffStrategy.d.ts from file deps/envoy-api/envoy/api/v2/core/backoff.proto +Writing src/generated//envoy/api/v2/core/HttpUri.d.ts from file deps/envoy-api/envoy/api/v2/core/http_uri.proto +Writing src/generated//envoy/api/v2/core/ApiVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ApiConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ApiConfigSource/ApiType.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/AggregatedConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/SelfConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/RateLimitSettings.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/GrpcService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/EnvoyGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/SslCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/GoogleLocalCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/ChannelCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/ServiceAccountJWTAccessCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/GoogleIAMCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/MetadataCredentialsFromPlugin.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/StsService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/auth/UpstreamTlsContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/DownstreamTlsContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/CommonTlsContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/CommonTlsContext/CombinedCertificateValidationContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/GenericSecret.d.ts from file deps/envoy-api/envoy/api/v2/auth/secret.proto +Writing src/generated//envoy/api/v2/auth/SdsSecretConfig.d.ts from file deps/envoy-api/envoy/api/v2/auth/secret.proto +Writing src/generated//envoy/api/v2/auth/Secret.d.ts from file deps/envoy-api/envoy/api/v2/auth/secret.proto +Writing src/generated//envoy/api/v2/auth/TlsParameters.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/TlsParameters/TlsProtocol.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/PrivateKeyProvider.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/TlsCertificate.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/TlsSessionTicketKeys.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/CertificateValidationContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/CertificateValidationContext/TrustChainVerification.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/route/VirtualHost.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/VirtualHost/TlsRequirementType.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/FilterAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/Route.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/WeightedCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/WeightedCluster/ClusterWeight.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteMatch.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteMatch/GrpcRouteMatchOptions.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteMatch/TlsContextMatchOptions.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/CorsPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/ClusterNotFoundResponseCode.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/InternalRedirectAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/RequestMirrorPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/Header.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/Cookie.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/ConnectionProperties.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/QueryParameter.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/FilterState.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/UpgradeConfig.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy/RetryPriority.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy/RetryHostPredicate.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy/RetryBackOff.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/HedgePolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RedirectAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RedirectAction/RedirectResponseCode.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/DirectResponseAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/Decorator.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/Tracing.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/VirtualCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/SourceCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/DestinationCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/RequestHeaders.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/RemoteAddress.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/GenericKey.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/HeaderValueMatch.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/HeaderMatcher.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/QueryParameterMatcher.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/config/listener/v2/ApiListener.d.ts from file deps/envoy-api/envoy/config/listener/v2/api_listener.proto +Writing src/generated//envoy/config/filter/accesslog/v2/AccessLog.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/AccessLogFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/ComparisonFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/ComparisonFilter/Op.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/StatusCodeFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/DurationFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/NotHealthCheckFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/TraceableFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/RuntimeFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/AndFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/OrFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/HeaderFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/ResponseFlagFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/GrpcStatusFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/GrpcStatusFilter/Status.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/ExtensionFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/type/Percent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent/DenominatorType.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/SemanticVersion.d.ts from file deps/envoy-api/envoy/type/semantic_version.proto +Writing src/generated//envoy/type/Int64Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/Int32Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/DoubleRange.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/matcher/RegexMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatcher/GoogleRE2.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatchAndSubstitute.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/StringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/matcher/ListStringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Literal.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Environment.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Header.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Metadata.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKey.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKey/PathSegment.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Request.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Route.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Cluster.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Host.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//udpa/annotations/MigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FieldMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FileMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/PackageVersionStatus.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//udpa/annotations/StatusAnnotation.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//validate/FieldRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/FloatRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DoubleRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BoolRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/StringRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/KnownRegex.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BytesRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/EnumRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MessageRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/RepeatedRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MapRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/AnyRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DurationRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/TimestampRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//google/protobuf/Duration.d.ts from file null +Writing src/generated//google/protobuf/DoubleValue.d.ts from file null +Writing src/generated//google/protobuf/FloatValue.d.ts from file null +Writing src/generated//google/protobuf/Int64Value.d.ts from file null +Writing src/generated//google/protobuf/UInt64Value.d.ts from file null +Writing src/generated//google/protobuf/Int32Value.d.ts from file null +Writing src/generated//google/protobuf/UInt32Value.d.ts from file null +Writing src/generated//google/protobuf/BoolValue.d.ts from file null +Writing src/generated//google/protobuf/StringValue.d.ts from file null +Writing src/generated//google/protobuf/BytesValue.d.ts from file null +Writing src/generated//google/protobuf/Any.d.ts from file null +Writing src/generated//google/protobuf/Struct.d.ts from file null +Writing src/generated//google/protobuf/Value.d.ts from file null +Writing src/generated//google/protobuf/NullValue.d.ts from file null +Writing src/generated//google/protobuf/ListValue.d.ts from file null +Writing src/generated//google/protobuf/Timestamp.d.ts from file null +Writing src/generated//google/protobuf/FileDescriptorSet.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ExtensionRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ReservedRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Type.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Label.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions/OptimizeMode.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MessageOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/CType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/JSType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption/NamePart.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo/Location.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo/Annotation.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/Empty.d.ts from file null +Writing src/generated//google/api/Http.d.ts from file node_modules/protobufjs/google/api/http.proto +Writing src/generated//google/api/HttpRule.d.ts from file node_modules/protobufjs/google/api/http.proto +Writing src/generated//google/api/CustomHttpPattern.d.ts from file node_modules/protobufjs/google/api/http.proto +Processing envoy/api/v2/route.proto +Writing src/generated//route.d.ts +Writing src/generated//envoy/api/v2/RouteConfiguration.d.ts from file deps/envoy-api/envoy/api/v2/route.proto +Writing src/generated//envoy/api/v2/Vhds.d.ts from file deps/envoy-api/envoy/api/v2/route.proto +Writing src/generated//envoy/api/v2/core/ApiVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ApiConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ApiConfigSource/ApiType.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/AggregatedConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/SelfConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/RateLimitSettings.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/RoutingPriority.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RequestMethod.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TrafficDirection.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Locality.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/BuildVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Extension.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Node.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Metadata.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeUInt32.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeDouble.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFeatureFlag.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValue.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValueOption.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderMap.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/DataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RemoteDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/AsyncDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TransportSocket.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFractionalPercent.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/ControlPlane.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/GrpcService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/EnvoyGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/SslCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/GoogleLocalCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/ChannelCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/ServiceAccountJWTAccessCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/GoogleIAMCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/MetadataCredentialsFromPlugin.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/StsService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/BackoffStrategy.d.ts from file deps/envoy-api/envoy/api/v2/core/backoff.proto +Writing src/generated//envoy/api/v2/core/HttpUri.d.ts from file deps/envoy-api/envoy/api/v2/core/http_uri.proto +Writing src/generated//envoy/api/v2/core/SocketOption.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/SocketOption/SocketState.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/Pipe.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress/Protocol.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/TcpKeepalive.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BindConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/Address.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/CidrRange.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/route/VirtualHost.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/VirtualHost/TlsRequirementType.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/FilterAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/Route.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/WeightedCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/WeightedCluster/ClusterWeight.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteMatch.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteMatch/GrpcRouteMatchOptions.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteMatch/TlsContextMatchOptions.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/CorsPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/ClusterNotFoundResponseCode.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/InternalRedirectAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/RequestMirrorPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/Header.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/Cookie.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/ConnectionProperties.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/QueryParameter.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/FilterState.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/UpgradeConfig.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy/RetryPriority.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy/RetryHostPredicate.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy/RetryBackOff.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/HedgePolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RedirectAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RedirectAction/RedirectResponseCode.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/DirectResponseAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/Decorator.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/Tracing.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/VirtualCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/SourceCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/DestinationCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/RequestHeaders.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/RemoteAddress.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/GenericKey.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/HeaderValueMatch.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/HeaderMatcher.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/QueryParameterMatcher.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/type/matcher/RegexMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatcher/GoogleRE2.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatchAndSubstitute.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/StringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/matcher/ListStringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/Int64Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/Int32Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/DoubleRange.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Literal.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Environment.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Header.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Metadata.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/SemanticVersion.d.ts from file deps/envoy-api/envoy/type/semantic_version.proto +Writing src/generated//envoy/type/Percent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent/DenominatorType.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKey.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKey/PathSegment.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Request.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Route.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Cluster.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Host.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//udpa/annotations/MigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FieldMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FileMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/PackageVersionStatus.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//udpa/annotations/StatusAnnotation.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//validate/FieldRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/FloatRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DoubleRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BoolRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/StringRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/KnownRegex.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BytesRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/EnumRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MessageRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/RepeatedRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MapRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/AnyRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DurationRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/TimestampRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//google/protobuf/DoubleValue.d.ts from file null +Writing src/generated//google/protobuf/FloatValue.d.ts from file null +Writing src/generated//google/protobuf/Int64Value.d.ts from file null +Writing src/generated//google/protobuf/UInt64Value.d.ts from file null +Writing src/generated//google/protobuf/Int32Value.d.ts from file null +Writing src/generated//google/protobuf/UInt32Value.d.ts from file null +Writing src/generated//google/protobuf/BoolValue.d.ts from file null +Writing src/generated//google/protobuf/StringValue.d.ts from file null +Writing src/generated//google/protobuf/BytesValue.d.ts from file null +Writing src/generated//google/protobuf/Duration.d.ts from file null +Writing src/generated//google/protobuf/Timestamp.d.ts from file null +Writing src/generated//google/protobuf/Any.d.ts from file null +Writing src/generated//google/protobuf/Struct.d.ts from file null +Writing src/generated//google/protobuf/Value.d.ts from file null +Writing src/generated//google/protobuf/NullValue.d.ts from file null +Writing src/generated//google/protobuf/ListValue.d.ts from file null +Writing src/generated//google/protobuf/FileDescriptorSet.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ExtensionRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ReservedRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Type.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Label.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions/OptimizeMode.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MessageOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/CType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/JSType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption/NamePart.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo/Location.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo/Annotation.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/Empty.d.ts from file null +Processing envoy/api/v2/cluster.proto +Writing src/generated//cluster.d.ts +Writing src/generated//envoy/api/v2/Cluster.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/DiscoveryType.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/LbPolicy.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/DnsLookupFamily.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/ClusterProtocolSelection.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/TransportSocketMatch.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/CustomClusterType.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/EdsClusterConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/LbSubsetConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/LbSubsetConfig/LbSubsetFallbackPolicy.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/LbSubsetConfig/LbSubsetSelector.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/LbSubsetConfig/LbSubsetSelector/LbSubsetSelectorFallbackPolicy.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/LeastRequestLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/RingHashLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/RingHashLbConfig/HashFunction.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/OriginalDstLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/CommonLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/CommonLbConfig/ZoneAwareLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/CommonLbConfig/LocalityWeightedLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/CommonLbConfig/ConsistentHashingLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/RefreshRate.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/LoadBalancingPolicy.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/LoadBalancingPolicy/Policy.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/UpstreamBindConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/UpstreamConnectionOptions.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/auth/UpstreamTlsContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/DownstreamTlsContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/CommonTlsContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/CommonTlsContext/CombinedCertificateValidationContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/TlsParameters.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/TlsParameters/TlsProtocol.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/PrivateKeyProvider.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/TlsCertificate.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/TlsSessionTicketKeys.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/CertificateValidationContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/CertificateValidationContext/TrustChainVerification.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/GenericSecret.d.ts from file deps/envoy-api/envoy/api/v2/auth/secret.proto +Writing src/generated//envoy/api/v2/auth/SdsSecretConfig.d.ts from file deps/envoy-api/envoy/api/v2/auth/secret.proto +Writing src/generated//envoy/api/v2/auth/Secret.d.ts from file deps/envoy-api/envoy/api/v2/auth/secret.proto +Writing src/generated//envoy/api/v2/core/ApiVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ApiConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ApiConfigSource/ApiType.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/AggregatedConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/SelfConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/RateLimitSettings.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/HealthStatus.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/Payload.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/HttpHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/TcpHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/RedisHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/GrpcHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/CustomHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/TlsOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/TcpProtocolOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/UpstreamHttpProtocolOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/HttpProtocolOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/HttpProtocolOptions/HeadersWithUnderscoresAction.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/Http1ProtocolOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/Http1ProtocolOptions/HeaderKeyFormat.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/Http1ProtocolOptions/HeaderKeyFormat/ProperCaseWords.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/Http2ProtocolOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/Http2ProtocolOptions/SettingsParameter.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/GrpcProtocolOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/Pipe.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress/Protocol.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/TcpKeepalive.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BindConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/Address.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/CidrRange.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/RoutingPriority.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RequestMethod.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TrafficDirection.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Locality.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/BuildVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Extension.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Node.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Metadata.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeUInt32.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeDouble.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFeatureFlag.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValue.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValueOption.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderMap.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/DataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RemoteDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/AsyncDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TransportSocket.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFractionalPercent.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/ControlPlane.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/GrpcService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/EnvoyGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/SslCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/GoogleLocalCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/ChannelCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/ServiceAccountJWTAccessCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/GoogleIAMCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/MetadataCredentialsFromPlugin.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/StsService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/BackoffStrategy.d.ts from file deps/envoy-api/envoy/api/v2/core/backoff.proto +Writing src/generated//envoy/api/v2/core/HttpUri.d.ts from file deps/envoy-api/envoy/api/v2/core/http_uri.proto +Writing src/generated//envoy/api/v2/core/SocketOption.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/SocketOption/SocketState.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/EventServiceConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/event_service_config.proto +Writing src/generated//envoy/api/v2/cluster/CircuitBreakers.d.ts from file deps/envoy-api/envoy/api/v2/cluster/circuit_breaker.proto +Writing src/generated//envoy/api/v2/cluster/CircuitBreakers/Thresholds.d.ts from file deps/envoy-api/envoy/api/v2/cluster/circuit_breaker.proto +Writing src/generated//envoy/api/v2/cluster/CircuitBreakers/Thresholds/RetryBudget.d.ts from file deps/envoy-api/envoy/api/v2/cluster/circuit_breaker.proto +Writing src/generated//envoy/api/v2/cluster/Filter.d.ts from file deps/envoy-api/envoy/api/v2/cluster/filter.proto +Writing src/generated//envoy/api/v2/cluster/OutlierDetection.d.ts from file deps/envoy-api/envoy/api/v2/cluster/outlier_detection.proto +Writing src/generated//envoy/api/v2/ClusterLoadAssignment.d.ts from file deps/envoy-api/envoy/api/v2/endpoint.proto +Writing src/generated//envoy/api/v2/ClusterLoadAssignment/Policy.d.ts from file deps/envoy-api/envoy/api/v2/endpoint.proto +Writing src/generated//envoy/api/v2/ClusterLoadAssignment/Policy/DropOverload.d.ts from file deps/envoy-api/envoy/api/v2/endpoint.proto +Writing src/generated//envoy/api/v2/endpoint/Endpoint.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/endpoint/Endpoint/HealthCheckConfig.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/endpoint/LbEndpoint.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/endpoint/LocalityLbEndpoints.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/type/Percent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent/DenominatorType.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/matcher/StringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/matcher/ListStringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/matcher/RegexMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatcher/GoogleRE2.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatchAndSubstitute.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/CodecClientType.d.ts from file deps/envoy-api/envoy/type/http.proto +Writing src/generated//envoy/type/SemanticVersion.d.ts from file deps/envoy-api/envoy/type/semantic_version.proto +Writing src/generated//envoy/type/Int64Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/Int32Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/DoubleRange.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//udpa/annotations/MigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FieldMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FileMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/PackageVersionStatus.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//udpa/annotations/StatusAnnotation.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//validate/FieldRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/FloatRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DoubleRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BoolRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/StringRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/KnownRegex.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BytesRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/EnumRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MessageRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/RepeatedRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MapRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/AnyRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DurationRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/TimestampRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//google/protobuf/Any.d.ts from file null +Writing src/generated//google/protobuf/Duration.d.ts from file null +Writing src/generated//google/protobuf/Struct.d.ts from file null +Writing src/generated//google/protobuf/Value.d.ts from file null +Writing src/generated//google/protobuf/NullValue.d.ts from file null +Writing src/generated//google/protobuf/ListValue.d.ts from file null +Writing src/generated//google/protobuf/DoubleValue.d.ts from file null +Writing src/generated//google/protobuf/FloatValue.d.ts from file null +Writing src/generated//google/protobuf/Int64Value.d.ts from file null +Writing src/generated//google/protobuf/UInt64Value.d.ts from file null +Writing src/generated//google/protobuf/Int32Value.d.ts from file null +Writing src/generated//google/protobuf/UInt32Value.d.ts from file null +Writing src/generated//google/protobuf/BoolValue.d.ts from file null +Writing src/generated//google/protobuf/StringValue.d.ts from file null +Writing src/generated//google/protobuf/BytesValue.d.ts from file null +Writing src/generated//google/protobuf/Timestamp.d.ts from file null +Writing src/generated//google/protobuf/Empty.d.ts from file null +Writing src/generated//google/protobuf/FileDescriptorSet.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ExtensionRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ReservedRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Type.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Label.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions/OptimizeMode.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MessageOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/CType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/JSType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption/NamePart.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo/Location.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo/Annotation.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/api/Http.d.ts from file node_modules/protobufjs/google/api/http.proto +Writing src/generated//google/api/HttpRule.d.ts from file node_modules/protobufjs/google/api/http.proto +Writing src/generated//google/api/CustomHttpPattern.d.ts from file node_modules/protobufjs/google/api/http.proto +Processing envoy/api/v2/endpoint.proto +Writing src/generated//endpoint.d.ts +Writing src/generated//envoy/api/v2/ClusterLoadAssignment.d.ts from file deps/envoy-api/envoy/api/v2/endpoint.proto +Writing src/generated//envoy/api/v2/ClusterLoadAssignment/Policy.d.ts from file deps/envoy-api/envoy/api/v2/endpoint.proto +Writing src/generated//envoy/api/v2/ClusterLoadAssignment/Policy/DropOverload.d.ts from file deps/envoy-api/envoy/api/v2/endpoint.proto +Writing src/generated//envoy/api/v2/endpoint/Endpoint.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/endpoint/Endpoint/HealthCheckConfig.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/endpoint/LbEndpoint.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/endpoint/LocalityLbEndpoints.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/core/RoutingPriority.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RequestMethod.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TrafficDirection.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Locality.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/BuildVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Extension.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Node.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Metadata.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeUInt32.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeDouble.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFeatureFlag.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValue.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValueOption.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderMap.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/DataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RemoteDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/AsyncDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TransportSocket.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFractionalPercent.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/ControlPlane.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Pipe.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress/Protocol.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/TcpKeepalive.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BindConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/Address.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/CidrRange.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/HealthStatus.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/Payload.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/HttpHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/TcpHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/RedisHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/GrpcHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/CustomHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/TlsOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/BackoffStrategy.d.ts from file deps/envoy-api/envoy/api/v2/core/backoff.proto +Writing src/generated//envoy/api/v2/core/HttpUri.d.ts from file deps/envoy-api/envoy/api/v2/core/http_uri.proto +Writing src/generated//envoy/api/v2/core/SocketOption.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/SocketOption/SocketState.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/EventServiceConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/event_service_config.proto +Writing src/generated//envoy/api/v2/core/GrpcService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/EnvoyGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/SslCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/GoogleLocalCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/ChannelCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/ServiceAccountJWTAccessCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/GoogleIAMCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/MetadataCredentialsFromPlugin.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/StsService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/type/Percent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent/DenominatorType.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/matcher/StringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/matcher/ListStringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/matcher/RegexMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatcher/GoogleRE2.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatchAndSubstitute.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/SemanticVersion.d.ts from file deps/envoy-api/envoy/type/semantic_version.proto +Writing src/generated//envoy/type/CodecClientType.d.ts from file deps/envoy-api/envoy/type/http.proto +Writing src/generated//envoy/type/Int64Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/Int32Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/DoubleRange.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//udpa/annotations/MigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FieldMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FileMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/PackageVersionStatus.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//udpa/annotations/StatusAnnotation.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//validate/FieldRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/FloatRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DoubleRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BoolRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/StringRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/KnownRegex.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BytesRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/EnumRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MessageRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/RepeatedRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MapRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/AnyRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DurationRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/TimestampRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//google/protobuf/Duration.d.ts from file null +Writing src/generated//google/protobuf/DoubleValue.d.ts from file null +Writing src/generated//google/protobuf/FloatValue.d.ts from file null +Writing src/generated//google/protobuf/Int64Value.d.ts from file null +Writing src/generated//google/protobuf/UInt64Value.d.ts from file null +Writing src/generated//google/protobuf/Int32Value.d.ts from file null +Writing src/generated//google/protobuf/UInt32Value.d.ts from file null +Writing src/generated//google/protobuf/BoolValue.d.ts from file null +Writing src/generated//google/protobuf/StringValue.d.ts from file null +Writing src/generated//google/protobuf/BytesValue.d.ts from file null +Writing src/generated//google/protobuf/Timestamp.d.ts from file null +Writing src/generated//google/protobuf/FileDescriptorSet.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ExtensionRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ReservedRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Type.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Label.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions/OptimizeMode.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MessageOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/CType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/JSType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption/NamePart.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo/Location.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo/Annotation.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/Any.d.ts from file null +Writing src/generated//google/protobuf/Struct.d.ts from file null +Writing src/generated//google/protobuf/Value.d.ts from file null +Writing src/generated//google/protobuf/NullValue.d.ts from file null +Writing src/generated//google/protobuf/ListValue.d.ts from file null +Writing src/generated//google/protobuf/Empty.d.ts from file null +Writing src/generated//google/api/Http.d.ts from file node_modules/protobufjs/google/api/http.proto +Writing src/generated//google/api/HttpRule.d.ts from file node_modules/protobufjs/google/api/http.proto +Writing src/generated//google/api/CustomHttpPattern.d.ts from file node_modules/protobufjs/google/api/http.proto +Success diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 6473bb32..0e445377 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.3", + "version": "1.2.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", @@ -15,18 +15,17 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "^0.6.0-pre6", + "@grpc/proto-loader": "^0.5.5", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", "@types/mocha": "^5.2.6", "@types/ncp": "^2.0.1", - "@types/node": "^12.7.5", "@types/pify": "^3.0.2", "@types/semver": "^6.0.1", + "@types/yargs": "^15.0.5", "clang-format": "^1.0.55", "execa": "^2.0.3", - "google-auth-library": "^6.0.0", "gts": "^2.0.0", "gulp": "^4.0.2", "gulp-mocha": "^6.0.0", @@ -36,7 +35,8 @@ "pify": "^4.0.1", "rimraf": "^3.0.2", "ts-node": "^8.3.0", - "typescript": "^3.7.2" + "typescript": "^3.7.2", + "yargs": "^15.4.1" }, "contributors": [ { @@ -48,7 +48,6 @@ "clean": "node -e 'require(\"rimraf\")(\"./build\", () => {})'", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", @@ -58,6 +57,8 @@ "posttest": "npm run check" }, "dependencies": { + "@types/node": "^12.12.47", + "google-auth-library": "^6.1.1", "semver": "^6.2.0" }, "files": [ diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 825342a5..32b85165 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -18,7 +18,7 @@ import * as http2 from 'http2'; import { CallCredentials } from './call-credentials'; -import { Status } from './constants'; +import { Propagate, Status } from './constants'; import { Filter, FilterFactory } from './filter'; import { FilterStackFactory, FilterStack } from './filter-stack'; import { Metadata } from './metadata'; @@ -27,6 +27,7 @@ import { ChannelImplementation } from './channel'; import { Subchannel } from './subchannel'; import * as logging from './logging'; import { LogVerbosity } from './constants'; +import { ServerSurfaceCall } from './server-call'; const TRACER_NAME = 'call_stream'; @@ -42,7 +43,7 @@ export interface CallStreamOptions { deadline: Deadline; flags: number; host: string; - parentCall: Call | null; + parentCall: ServerSurfaceCall | null; } export type PartialCallStreamOptions = Partial; @@ -218,6 +219,11 @@ export class Http2CallStream implements Call { metadata: new Metadata(), }); }; + if (this.options.parentCall && this.options.flags & Propagate.CANCELLATION) { + this.options.parentCall.on('cancelled', () => { + this.cancelWithStatus(Status.CANCELLED, 'Cancelled by parent call'); + }); + } } private outputStatus() { @@ -227,7 +233,15 @@ export class Http2CallStream implements Call { const filteredStatus = this.filterStack.receiveTrailers( this.finalStatus! ); - this.listener?.onReceiveStatus(filteredStatus); + /* We delay the actual action of bubbling up the status to insulate the + * cleanup code in this class from any errors that may be thrown in the + * upper layers as a result of bubbling up the status. In particular, + * if the status is not OK, the "error" event may be emitted + * synchronously at the top level, which will result in a thrown error if + * the user does not handle that event. */ + process.nextTick(() => { + this.listener?.onReceiveStatus(filteredStatus); + }); if (this.subchannel) { this.subchannel.callUnref(); this.subchannel.removeDisconnectListener(this.disconnectListener); @@ -602,6 +616,7 @@ export class Http2CallStream implements Call { } else { code = http2.constants.NGHTTP2_CANCEL; } + this.trace('close http2 stream with code ' + code); this.http2Stream.close(code); } } @@ -614,7 +629,11 @@ export class Http2CallStream implements Call { } getDeadline(): Deadline { - return this.options.deadline; + if (this.options.parentCall && this.options.flags & Propagate.DEADLINE) { + return this.options.parentCall.getDeadline(); + } else { + return this.options.deadline; + } } getCredentials(): CallCredentials { @@ -630,7 +649,7 @@ export class Http2CallStream implements Call { } getPeer(): string { - throw new Error('Not yet implemented'); + return this.subchannel?.getAddress() ?? this.channel.getTarget(); } getMethod(): string { diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index 0d88ef15..cfe37ecf 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -93,7 +93,7 @@ export class ClientUnaryCallImpl extends EventEmitter } getPeer(): string { - return this.call?.getPeer() ?? ''; + return this.call?.getPeer() ?? 'unknown'; } } @@ -109,7 +109,7 @@ export class ClientReadableStreamImpl extends Readable } getPeer(): string { - return this.call?.getPeer() ?? ''; + return this.call?.getPeer() ?? 'unknown'; } _read(_size: number): void { @@ -129,7 +129,7 @@ export class ClientWritableStreamImpl extends Writable } getPeer(): string { - return this.call?.getPeer() ?? ''; + return this.call?.getPeer() ?? 'unknown'; } _write(chunk: RequestType, encoding: string, cb: WriteCallback) { @@ -164,7 +164,7 @@ export class ClientDuplexStreamImpl extends Duplex } getPeer(): string { - return this.call?.getPeer() ?? ''; + return this.call?.getPeer() ?? 'unknown'; } _read(_size: number): void { diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 8c4756ec..df6cbb2b 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -25,6 +25,7 @@ export interface ChannelOptions { 'grpc.default_authority'?: string; 'grpc.keepalive_time_ms'?: number; 'grpc.keepalive_timeout_ms'?: number; + 'grpc.keepalive_permit_without_calls'?: number; 'grpc.service_config'?: string; 'grpc.max_concurrent_streams'?: number; 'grpc.initial_reconnect_backoff_ms'?: number; @@ -33,7 +34,9 @@ export interface ChannelOptions { 'grpc.max_send_message_length'?: number; 'grpc.max_receive_message_length'?: number; 'grpc.enable_http_proxy'?: number; - [key: string]: string | number | undefined; + 'grpc.http_connect_target'?: string; + 'grpc.http_connect_creds'?: string; + [key: string]: any; } /** @@ -47,6 +50,7 @@ export const recognizedOptions = { 'grpc.default_authority': true, 'grpc.keepalive_time_ms': true, 'grpc.keepalive_timeout_ms': true, + 'grpc.keepalive_permit_without_calls': true, 'grpc.service_config': true, 'grpc.max_concurrent_streams': true, 'grpc.initial_reconnect_backoff_ms': true, diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index fe85dec0..e1a76c09 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -28,27 +28,33 @@ import { SubchannelPool, getSubchannelPool } from './subchannel-pool'; import { ChannelControlHelper } from './load-balancer'; import { UnavailablePicker, Picker, PickResultType } from './picker'; import { Metadata } from './metadata'; -import { Status, LogVerbosity } from './constants'; +import { Status, LogVerbosity, Propagate } from './constants'; import { FilterStackFactory } from './filter-stack'; import { CallCredentialsFilterFactory } from './call-credentials-filter'; import { DeadlineFilterFactory } from './deadline-filter'; import { CompressionFilterFactory } from './compression-filter'; import { getDefaultAuthority, mapUriDefaultScheme } from './resolver'; -import { ServiceConfig, validateServiceConfig } from './service-config'; import { trace, log } from './logging'; import { SubchannelAddress } from './subchannel'; import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; import { mapProxyName } from './http_proxy'; import { GrpcUri, parseUri, uriToString } from './uri-parser'; +import { ServerSurfaceCall } from './server-call'; +import { SurfaceCall } from './call'; export enum ConnectivityState { + IDLE, CONNECTING, READY, TRANSIENT_FAILURE, - IDLE, SHUTDOWN, } +/** + * See https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args + */ +const MAX_TIMEOUT_TIME = 2147483647; + let nextCallNumber = 0; function getNewCallNumber(): number { @@ -114,14 +120,14 @@ export interface Channel { method: string, deadline: Deadline, host: string | null | undefined, - parentCall: any, // eslint-disable-line @typescript-eslint/no-explicit-any + parentCall: ServerSurfaceCall | null, propagateFlags: number | null | undefined ): Call; } interface ConnectivityStateWatcher { currentState: ConnectivityState; - timer: NodeJS.Timeout; + timer: NodeJS.Timeout | null; callback: (error?: Error) => void; } @@ -138,6 +144,14 @@ export class ChannelImplementation implements Channel { private defaultAuthority: string; private filterStackFactory: FilterStackFactory; private target: GrpcUri; + /** + * This timer does not do anything on its own. Its purpose is to hold the + * event loop open while there are any pending calls for the channel that + * have not yet been assigned to specific subchannels. In other words, + * the invariant is that callRefTimer is reffed if and only if pickQueue + * is non-empty. + */ + private callRefTimer: NodeJS.Timer; constructor( target: string, private readonly credentials: ChannelCredentials, @@ -178,6 +192,10 @@ export class ChannelImplementation implements Channel { `Could not find a default scheme for target name "${target}"` ); } + + this.callRefTimer = setInterval(() => {}, MAX_TIMEOUT_TIME); + this.callRefTimer.unref?.(); + if (this.options['grpc.default_authority']) { this.defaultAuthority = this.options['grpc.default_authority'] as string; } else { @@ -207,6 +225,7 @@ export class ChannelImplementation implements Channel { updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.currentPicker = picker; const queueCopy = this.pickQueue.slice(); + this.callRefTimer.unref?.(); this.pickQueue = []; for (const { callStream, callMetadata } of queueCopy) { this.tryPick(callStream, callMetadata); @@ -220,20 +239,10 @@ export class ChannelImplementation implements Channel { ); }, }; - // TODO(murgatroid99): check channel arg for default service config - let defaultServiceConfig: ServiceConfig = { - loadBalancingConfig: [], - methodConfig: [], - }; - if (options['grpc.service_config']) { - defaultServiceConfig = validateServiceConfig( - JSON.parse(options['grpc.service_config']!) - ); - } this.resolvingLoadBalancer = new ResolvingLoadBalancer( this.target, channelControlHelper, - defaultServiceConfig + options ); this.filterStackFactory = new FilterStackFactory([ new CallCredentialsFilterFactory(this), @@ -243,6 +252,11 @@ export class ChannelImplementation implements Channel { ]); } + private pushPick(callStream: Http2CallStream, callMetadata: Metadata) { + this.callRefTimer.ref?.(); + this.pickQueue.push({ callStream, callMetadata }); + } + /** * Check the picker output for the given call and corresponding metadata, * and take any relevant actions. Should not be called while iterating @@ -287,7 +301,7 @@ export class ChannelImplementation implements Channel { ' has state ' + ConnectivityState[pickResult.subchannel!.getConnectivityState()] ); - this.pickQueue.push({ callStream, callMetadata }); + this.pushPick(callStream, callMetadata); break; } /* We need to clone the callMetadata here because the transparent @@ -378,11 +392,11 @@ export class ChannelImplementation implements Channel { } break; case PickResultType.QUEUE: - this.pickQueue.push({ callStream, callMetadata }); + this.pushPick(callStream, callMetadata); break; case PickResultType.TRANSIENT_FAILURE: if (callMetadata.getOptions().waitForReady) { - this.pickQueue.push({ callStream, callMetadata }); + this.pushPick(callStream, callMetadata); } else { callStream.cancelWithStatus( pickResult.status!.code, @@ -390,6 +404,12 @@ export class ChannelImplementation implements Channel { ); } break; + case PickResultType.DROP: + callStream.cancelWithStatus( + pickResult.status!.code, + pickResult.status!.details + ); + break; default: throw new Error( `Invalid state: unknown pickResultType ${pickResult.pickResultType}` @@ -422,7 +442,9 @@ export class ChannelImplementation implements Channel { const watchersCopy = this.connectivityStateWatchers.slice(); for (const watcherObject of watchersCopy) { if (newState !== watcherObject.currentState) { - clearTimeout(watcherObject.timer); + if(watcherObject.timer) { + clearTimeout(watcherObject.timer); + } this.removeConnectivityStateWatcher(watcherObject); watcherObject.callback(); } @@ -436,6 +458,7 @@ export class ChannelImplementation implements Channel { close() { this.resolvingLoadBalancer.destroy(); this.updateState(ConnectivityState.SHUTDOWN); + clearInterval(this.callRefTimer); this.subchannelPool.unrefUnusedSubchannels(); } @@ -457,25 +480,29 @@ export class ChannelImplementation implements Channel { deadline: Date | number, callback: (error?: Error) => void ): void { - const deadlineDate: Date = - deadline instanceof Date ? deadline : new Date(deadline); - const now = new Date(); - if (deadlineDate <= now) { - process.nextTick( - callback, - new Error('Deadline passed without connectivity state change') - ); - return; - } - const watcherObject = { - currentState, - callback, - timer: setTimeout(() => { + let timer = null; + if(deadline !== Infinity) { + const deadlineDate: Date = + deadline instanceof Date ? deadline : new Date(deadline); + const now = new Date(); + if (deadline === -Infinity || deadlineDate <= now) { + process.nextTick( + callback, + new Error('Deadline passed without connectivity state change') + ); + return; + } + timer = setTimeout(() => { this.removeConnectivityStateWatcher(watcherObject); callback( new Error('Deadline passed without connectivity state change') ); - }, deadlineDate.getTime() - now.getTime()), + }, deadlineDate.getTime() - now.getTime()) + } + const watcherObject = { + currentState, + callback, + timer }; this.connectivityStateWatchers.push(watcherObject); } @@ -484,7 +511,7 @@ export class ChannelImplementation implements Channel { method: string, deadline: Deadline, host: string | null | undefined, - parentCall: any, // eslint-disable-line @typescript-eslint/no-explicit-any + parentCall: ServerSurfaceCall | null, propagateFlags: number | null | undefined ): Call { if (typeof method !== 'string') { @@ -512,9 +539,9 @@ export class ChannelImplementation implements Channel { ); const finalOptions: CallStreamOptions = { deadline: deadline, - flags: propagateFlags || 0, - host: host || this.defaultAuthority, - parentCall: parentCall || null, + flags: propagateFlags ?? Propagate.DEFAULTS, + host: host ?? this.defaultAuthority, + parentCall: parentCall, }; const stream: Http2CallStream = new Http2CallStream( method, diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index fe36ea36..09e7f5aa 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -311,21 +311,11 @@ export class InterceptingCall implements InterceptingCallInterface { } function getCall(channel: Channel, path: string, options: CallOptions): Call { - let deadline; - let host; - const parent = null; - let propagateFlags; - let credentials; - if (options) { - deadline = options.deadline; - host = options.host; - - propagateFlags = options.propagate_flags; - credentials = options.credentials; - } - if (deadline === undefined) { - deadline = Infinity; - } + const deadline = options.deadline ?? Infinity; + const host = options.host; + const parent = options.parent ?? null; + const propagateFlags = options.propagate_flags; + const credentials = options.credentials; const call = channel.createCall(path, deadline, host, parent, propagateFlags); if (credentials) { call.setCredentials(credentials); diff --git a/packages/grpc-js/src/constants.ts b/packages/grpc-js/src/constants.ts index e760658d..d30b78f0 100644 --- a/packages/grpc-js/src/constants.ts +++ b/packages/grpc-js/src/constants.ts @@ -50,7 +50,8 @@ export enum Propagate { CENSUS_STATS_CONTEXT = 2, CENSUS_TRACING_CONTEXT = 4, CANCELLATION = 8, - DEFAULTS = 65536, + // https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/propagation_bits.h#L43 + DEFAULTS = 0xffff | Propagate.DEADLINE | Propagate.CENSUS_STATS_CONTEXT | Propagate.CENSUS_TRACING_CONTEXT | Propagate.CANCELLATION, } // -1 means unlimited diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts new file mode 100644 index 00000000..b88f124a --- /dev/null +++ b/packages/grpc-js/src/experimental.ts @@ -0,0 +1,13 @@ +export { trace } from './logging'; +export { Resolver, ResolverListener, registerResolver } from './resolver'; +export { GrpcUri, uriToString } from './uri-parser'; +export { ServiceConfig } from './service-config'; +export { createGoogleDefaultCredentials } from './channel-credentials'; +export { BackoffTimeout } from './backoff-timeout'; +export { LoadBalancer, LoadBalancingConfig, ChannelControlHelper, registerLoadBalancerType, getFirstUsableConfig, validateLoadBalancingConfig } from './load-balancer'; +export { SubchannelAddress, subchannelAddressToString } from './subchannel'; +export { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +export { Picker, UnavailablePicker, QueuePicker, PickResult, PickArgs, PickResultType } from './picker'; +export { Call as CallStream } from './call-stream'; +export { Filter, BaseFilter, FilterFactory } from './filter'; +export { FilterStackFactory } from './filter-stack'; \ No newline at end of file diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 8411e117..f6921378 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -84,8 +84,16 @@ function getProxyInfo(): ProxyInfo { userCred = proxyUrl.username; } } + const hostname = proxyUrl.hostname; + let port = proxyUrl.port; + /* The proxy URL uses the scheme "http:", which has a default port number of + * 80. We need to set that explicitly here if it is omitted because otherwise + * it will use gRPC's default port 443. */ + if (port === '') { + port = '80'; + } const result: ProxyInfo = { - address: proxyUrl.host, + address: `${hostname}:${port}` }; if (userCred) { result.creds = userCred; @@ -215,8 +223,10 @@ export function getProxiedConnection( * connection to a TLS connection. * This is a workaround for https://github.com/nodejs/node/issues/32922 * See https://github.com/grpc/grpc-node/pull/1369 for more info. */ - const remoteHost = getDefaultAuthority(parsedTarget); - + const targetPath = getDefaultAuthority(parsedTarget); + const hostPort = splitHostPort(targetPath); + const remoteHost = hostPort?.host ?? targetPath; + const cts = tls.connect( { host: remoteHost, diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index f79a369b..e90ac4be 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -57,6 +57,7 @@ import { StatusBuilder } from './status-builder'; import { handleBidiStreamingCall, handleServerStreamingCall, + handleClientStreamingCall, handleUnaryCall, sendUnaryData, ServerUnaryCall, @@ -186,7 +187,7 @@ export { /**** Server ****/ -export { handleBidiStreamingCall, handleServerStreamingCall, handleUnaryCall }; +export { handleBidiStreamingCall, handleServerStreamingCall, handleUnaryCall, handleClientStreamingCall }; /* eslint-disable @typescript-eslint/no-explicit-any */ export type Call = @@ -245,6 +246,11 @@ export { export { GrpcObject } from './make-client'; +export { ChannelOptions } from './channel-options'; + +import * as experimental from './experimental'; +export { experimental }; + import * as resolver from './resolver'; import * as load_balancer from './load-balancer'; diff --git a/packages/grpc-js/src/load-balancer-cds.ts b/packages/grpc-js/src/load-balancer-cds.ts deleted file mode 100644 index 82346978..00000000 --- a/packages/grpc-js/src/load-balancer-cds.ts +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2020 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. - * - */ - -import { - LoadBalancer, - ChannelControlHelper, - registerLoadBalancerType, -} from './load-balancer'; -import { SubchannelAddress } from './subchannel'; -import { - LoadBalancingConfig, - isCdsLoadBalancingConfig, - EdsLbConfig, - CdsLoadBalancingConfig, -} from './load-balancing-config'; -import { XdsClient, Watcher } from './xds-client'; -import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; -import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; -import { ConnectivityState } from './channel'; -import { UnavailablePicker } from './picker'; -import { Status } from './constants'; -import { Metadata } from './metadata'; - -const TYPE_NAME = 'cds'; - -export class CdsLoadBalancer implements LoadBalancer { - private childBalancer: ChildLoadBalancerHandler; - private xdsClient: XdsClient | null = null; - private watcher: Watcher; - - private isWatcherActive = false; - - private latestCdsUpdate: Cluster__Output | null = null; - - private latestConfig: CdsLoadBalancingConfig | null = null; - private latestAttributes: { [key: string]: unknown } = {}; - - constructor(private readonly channelControlHelper: ChannelControlHelper) { - this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper); - this.watcher = { - onValidUpdate: (update) => { - this.latestCdsUpdate = update; - const edsConfig: EdsLbConfig = { - cluster: update.name, - edsServiceName: - update.eds_cluster_config!.service_name === '' - ? undefined - : update.eds_cluster_config!.service_name, - localityPickingPolicy: [], - endpointPickingPolicy: [], - }; - if (update.lrs_server?.self) { - /* the lrs_server.self field indicates that the same server should be - * used for load reporting as for other xDS operations. Setting - * lrsLoadReportingServerName to the empty string sets that behavior. - * Otherwise, if the field is omitted, load reporting is disabled. */ - edsConfig.lrsLoadReportingServerName = ''; - } - this.childBalancer.updateAddressList( - [], - { name: 'eds', eds: edsConfig }, - this.latestAttributes - ); - }, - onResourceDoesNotExist: () => { - this.xdsClient?.removeClusterWatcher( - this.latestConfig!.cds.cluster, - this.watcher - ); - this.isWatcherActive = false; - }, - onTransientError: (status) => { - if (this.latestCdsUpdate === null) { - channelControlHelper.updateState( - ConnectivityState.TRANSIENT_FAILURE, - new UnavailablePicker({ - code: Status.UNAVAILABLE, - details: `xDS request failed with error ${status.details}`, - metadata: new Metadata(), - }) - ); - } - }, - }; - } - - updateAddressList( - addressList: SubchannelAddress[], - lbConfig: LoadBalancingConfig, - attributes: { [key: string]: unknown } - ): void { - if (!isCdsLoadBalancingConfig(lbConfig)) { - return; - } - if (!(attributes.xdsClient instanceof XdsClient)) { - return; - } - this.xdsClient = attributes.xdsClient; - this.latestAttributes = attributes; - - /* If the cluster is changing, disable the old watcher before adding the new - * one */ - if ( - this.isWatcherActive && - this.latestConfig?.cds.cluster !== lbConfig.cds.cluster - ) { - this.xdsClient.removeClusterWatcher( - this.latestConfig!.cds.cluster, - this.watcher - ); - /* Setting isWatcherActive to false here lets us have one code path for - * calling addClusterWatcher */ - this.isWatcherActive = false; - /* If we have a new name, the latestCdsUpdate does not correspond to - * the new config, so it is no longer valid */ - this.latestCdsUpdate = null; - } - - this.latestConfig = lbConfig; - - if (!this.isWatcherActive) { - this.xdsClient.addClusterWatcher(lbConfig.cds.cluster, this.watcher); - this.isWatcherActive = true; - } - } - exitIdle(): void { - this.childBalancer.exitIdle(); - } - resetBackoff(): void { - this.childBalancer.resetBackoff(); - } - destroy(): void { - this.childBalancer.destroy(); - if (this.isWatcherActive) { - this.xdsClient?.removeClusterWatcher( - this.latestConfig!.cds.cluster, - this.watcher - ); - } - } - getTypeName(): string { - return TYPE_NAME; - } -} - -export function setup() { - registerLoadBalancerType(TYPE_NAME, CdsLoadBalancer); -} diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index 158108f0..337174c0 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -19,9 +19,9 @@ import { LoadBalancer, ChannelControlHelper, createLoadBalancer, + LoadBalancingConfig } from './load-balancer'; import { SubchannelAddress, Subchannel } from './subchannel'; -import { LoadBalancingConfig } from './load-balancing-config'; import { ChannelOptions } from './channel-options'; import { ConnectivityState } from './channel'; import { Picker } from './picker'; @@ -90,10 +90,10 @@ export class ChildLoadBalancerHandler implements LoadBalancer { let childToUpdate: LoadBalancer; if ( this.currentChild === null || - this.currentChild.getTypeName() !== lbConfig.name + this.currentChild.getTypeName() !== lbConfig.getLoadBalancerName() ) { const newHelper = new this.ChildPolicyHelper(this); - const newChild = createLoadBalancer(lbConfig.name, newHelper)!; + const newChild = createLoadBalancer(lbConfig, newHelper)!; newHelper.setChild(newChild); if (this.currentChild === null) { this.currentChild = newChild; @@ -133,9 +133,11 @@ export class ChildLoadBalancerHandler implements LoadBalancer { destroy(): void { if (this.currentChild) { this.currentChild.destroy(); + this.currentChild = null; } if (this.pendingChild) { this.pendingChild.destroy(); + this.pendingChild = null; } } getTypeName(): string { diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts deleted file mode 100644 index 24b464af..00000000 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ /dev/null @@ -1,334 +0,0 @@ -/* - * Copyright 2020 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. - * - */ - -import { - LoadBalancer, - ChannelControlHelper, - registerLoadBalancerType, - getFirstUsableConfig, -} from './load-balancer'; -import { SubchannelAddress } from './subchannel'; -import { - LoadBalancingConfig, - isEdsLoadBalancingConfig, - EdsLoadBalancingConfig, - PriorityLbConfig, - PriorityChild, - WeightedTarget, - PriorityLoadBalancingConfig, -} from './load-balancing-config'; -import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; -import { XdsClient, Watcher } from './xds-client'; -import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; -import { ConnectivityState } from './channel'; -import { UnavailablePicker } from './picker'; -import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; -import { LocalitySubchannelAddress } from './load-balancer-priority'; -import { Status } from './constants'; -import { Metadata } from './metadata'; - -const TYPE_NAME = 'eds'; - -function localityToName(locality: Locality__Output) { - return `{region=${locality.region},zone=${locality.zone},sub_zone=${locality.sub_zone}}`; -} - -/** - * This class load balances over a cluster by making an EDS request and then - * transforming the result into a configuration for another load balancing - * policy. - */ -export class EdsLoadBalancer implements LoadBalancer { - /** - * The child load balancer that will handle balancing the results of the EDS - * requests. - */ - private childBalancer: ChildLoadBalancerHandler; - private xdsClient: XdsClient | null = null; - private edsServiceName: string | null = null; - private watcher: Watcher; - /** - * Indicates whether the watcher has already been passed to this.xdsClient - * and is getting updates. - */ - private isWatcherActive = false; - - private lastestConfig: EdsLoadBalancingConfig | null = null; - private latestAttributes: { [key: string]: unknown } = {}; - private latestEdsUpdate: ClusterLoadAssignment__Output | null = null; - - /** - * The priority of each locality the last time we got an update. - */ - private localityPriorities: Map = new Map(); - /** - * The name we assigned to each priority number the last time we got an - * update. - */ - private priorityNames: string[] = []; - - private nextPriorityChildNumber = 0; - - constructor(private readonly channelControlHelper: ChannelControlHelper) { - this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper); - this.watcher = { - onValidUpdate: (update) => { - this.latestEdsUpdate = update; - this.updateChild(); - }, - onResourceDoesNotExist: () => { - this.xdsClient?.removeEndpointWatcher( - this.edsServiceName!, - this.watcher - ); - this.isWatcherActive = false; - }, - onTransientError: (status) => { - if (this.latestEdsUpdate === null) { - channelControlHelper.updateState( - ConnectivityState.TRANSIENT_FAILURE, - new UnavailablePicker({ - code: Status.UNAVAILABLE, - details: `xDS request failed with error ${status.details}`, - metadata: new Metadata(), - }) - ); - } - }, - }; - } - - /** - * Should be called when this balancer gets a new config and when the - * XdsClient returns a new ClusterLoadAssignment. - */ - private updateChild() { - if (!(this.lastestConfig && this.latestEdsUpdate)) { - return; - } - /** - * Maps each priority number to the list of localities with that priority, - * and the list of addresses associated with each locality. - */ - const priorityList: { - locality: Locality__Output; - weight: number; - addresses: SubchannelAddress[]; - }[][] = []; - const newLocalityPriorities: Map = new Map< - string, - number - >(); - /* We are given a list of localities, each of which has a priority. This - * loop consolidates localities into buckets by priority, while also - * simplifying the data structure to make the later steps simpler */ - for (const endpoint of this.latestEdsUpdate.endpoints) { - let localityArray = priorityList[endpoint.priority]; - if (localityArray === undefined) { - localityArray = []; - priorityList[endpoint.priority] = localityArray; - } - const addresses: SubchannelAddress[] = endpoint.lb_endpoints.map( - (lbEndpoint) => { - /* The validator in the XdsClient class ensures that each endpoint has - * a socket_address with an IP address and a port_value. */ - const socketAddress = lbEndpoint.endpoint!.address!.socket_address!; - return { - host: socketAddress.address!, - port: socketAddress.port_value!, - }; - } - ); - localityArray.push({ - locality: endpoint.locality!, - addresses: addresses, - weight: endpoint.load_balancing_weight?.value ?? 0, - }); - newLocalityPriorities.set( - localityToName(endpoint.locality!), - endpoint.priority - ); - } - - const newPriorityNames: string[] = []; - const addressList: LocalitySubchannelAddress[] = []; - const priorityChildren: Map = new Map< - string, - PriorityChild - >(); - /* The algorithm here is as follows: for each priority we are given, from - * high to low: - * - If the previous mapping had any of the same localities at the same or - * a lower priority, use the matching name from the highest such - * priority, unless the new mapping has already used that name. - * - Otherwise, construct a new name using this.nextPriorityChildNumber. - */ - for (const [priority, localityArray] of priorityList.entries()) { - if (localityArray === undefined) { - continue; - } - /** - * Highest (smallest number) priority value that any of the localities in - * this locality array had a in the previous mapping. - */ - let highestOldPriority = Infinity; - for (const localityObj of localityArray) { - const oldPriority = this.localityPriorities.get( - localityToName(localityObj.locality) - ); - if ( - oldPriority !== undefined && - oldPriority >= priority && - oldPriority < highestOldPriority - ) { - highestOldPriority = oldPriority; - } - } - let newPriorityName: string; - if (highestOldPriority === Infinity) { - /* No existing priority at or below the same number as the priority we - * are looking at had any of the localities in this priority. So, we - * use a new name. */ - newPriorityName = `child${this.nextPriorityChildNumber++}`; - } else { - const newName = this.priorityNames[highestOldPriority]; - if (newPriorityNames.indexOf(newName) < 0) { - newPriorityName = newName; - } else { - newPriorityName = `child${this.nextPriorityChildNumber++}`; - } - } - newPriorityNames[priority] = newPriorityName; - - const childTargets: Map = new Map< - string, - WeightedTarget - >(); - for (const localityObj of localityArray) { - childTargets.set(localityToName(localityObj.locality), { - weight: localityObj.weight, - /* TODO(murgatroid99): Insert an lrs config around the round_robin - * config after implementing lrs */ - /* Use the endpoint picking policy from the config, default to - * round_robin. */ - child_policy: [ - ...this.lastestConfig.eds.endpointPickingPolicy, - { name: 'round_robin', round_robin: {} }, - ], - }); - for (const address of localityObj.addresses) { - addressList.push({ - localityPath: [ - newPriorityName, - localityToName(localityObj.locality), - ], - ...address, - }); - } - } - - priorityChildren.set(newPriorityName, { - config: [ - { - name: 'weighted_target', - weighted_target: { - targets: childTargets, - }, - }, - ], - }); - } - const childConfig: PriorityLoadBalancingConfig = { - name: 'priority', - priority: { - children: priorityChildren, - /* Contract the priority names array if it is sparse. This config only - * cares about the order of priorities, not their specific numbers */ - priorities: newPriorityNames.filter((value) => value !== undefined), - }, - }; - this.childBalancer.updateAddressList( - addressList, - childConfig, - this.latestAttributes - ); - - this.localityPriorities = newLocalityPriorities; - this.priorityNames = newPriorityNames; - } - - updateAddressList( - addressList: SubchannelAddress[], - lbConfig: LoadBalancingConfig, - attributes: { [key: string]: unknown } - ): void { - if (!isEdsLoadBalancingConfig(lbConfig)) { - return; - } - if (!(attributes.xdsClient instanceof XdsClient)) { - return; - } - this.lastestConfig = lbConfig; - this.latestAttributes = attributes; - this.xdsClient = attributes.xdsClient; - const newEdsServiceName = - lbConfig.eds.edsServiceName ?? lbConfig.eds.cluster; - - /* If the name is changing, disable the old watcher before adding the new - * one */ - if (this.isWatcherActive && this.edsServiceName !== newEdsServiceName) { - this.xdsClient.removeEndpointWatcher(this.edsServiceName!, this.watcher); - /* Setting isWatcherActive to false here lets us have one code path for - * calling addEndpointWatcher */ - this.isWatcherActive = false; - /* If we have a new name, the latestEdsUpdate does not correspond to - * the new config, so it is no longer valid */ - this.latestEdsUpdate = null; - } - - this.edsServiceName = newEdsServiceName; - - if (!this.isWatcherActive) { - this.xdsClient.addEndpointWatcher(this.edsServiceName, this.watcher); - this.isWatcherActive = true; - } - - /* If updateAddressList is called after receiving an update and the update - * is still valid, we want to update the child config with the information - * in the new EdsLoadBalancingConfig. */ - this.updateChild(); - } - exitIdle(): void { - this.childBalancer.exitIdle(); - } - resetBackoff(): void { - this.childBalancer.resetBackoff(); - } - destroy(): void { - if (this.edsServiceName) { - this.xdsClient?.removeEndpointWatcher(this.edsServiceName, this.watcher); - } - this.childBalancer.destroy(); - } - getTypeName(): string { - return TYPE_NAME; - } -} - -export function setup() { - registerLoadBalancerType(TYPE_NAME, EdsLoadBalancer); -} diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index b5cea06c..31dc1784 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -19,6 +19,7 @@ import { LoadBalancer, ChannelControlHelper, registerLoadBalancerType, + LoadBalancingConfig } from './load-balancer'; import { ConnectivityState } from './channel'; import { @@ -29,7 +30,6 @@ import { PickResultType, UnavailablePicker, } from './picker'; -import { LoadBalancingConfig } from './load-balancing-config'; import { Subchannel, ConnectivityStateListener, @@ -53,6 +53,24 @@ const TYPE_NAME = 'pick_first'; */ const CONNECTION_DELAY_INTERVAL_MS = 250; +export class PickFirstLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + + constructor() {} + + toJsonObject(): object { + return { + [TYPE_NAME]: {} + }; + } + + static createFromJson(obj: any) { + return new PickFirstLoadBalancingConfig(); + } +} + /** * Picker for a `PickFirstLoadBalancer` in the READY state. Always returns the * picked subchannel. @@ -439,5 +457,5 @@ export class PickFirstLoadBalancer implements LoadBalancer { } export function setup(): void { - registerLoadBalancerType(TYPE_NAME, PickFirstLoadBalancer); + registerLoadBalancerType(TYPE_NAME, PickFirstLoadBalancer, PickFirstLoadBalancingConfig); } diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 8ee2201a..fc9bef0c 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -19,6 +19,7 @@ import { LoadBalancer, ChannelControlHelper, registerLoadBalancerType, + LoadBalancingConfig } from './load-balancer'; import { ConnectivityState } from './channel'; import { @@ -29,7 +30,6 @@ import { PickResultType, UnavailablePicker, } from './picker'; -import { LoadBalancingConfig } from './load-balancing-config'; import { Subchannel, ConnectivityStateListener, @@ -47,6 +47,24 @@ function trace(text: string): void { const TYPE_NAME = 'round_robin'; +class RoundRobinLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + + constructor() {} + + toJsonObject(): object { + return { + [TYPE_NAME]: {} + }; + } + + static createFromJson(obj: any) { + return new RoundRobinLoadBalancingConfig(); + } +} + class RoundRobinPicker implements Picker { constructor( private readonly subchannelList: Subchannel[], @@ -231,5 +249,5 @@ export class RoundRobinLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, RoundRobinLoadBalancer); + registerLoadBalancerType(TYPE_NAME, RoundRobinLoadBalancer, RoundRobinLoadBalancingConfig); } diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 227bbe9c..8d5c7c83 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -19,13 +19,8 @@ import { ChannelOptions } from './channel-options'; import { Subchannel, SubchannelAddress } from './subchannel'; import { ConnectivityState } from './channel'; import { Picker } from './picker'; -import { LoadBalancingConfig } from './load-balancing-config'; import * as load_balancer_pick_first from './load-balancer-pick-first'; import * as load_balancer_round_robin from './load-balancer-round-robin'; -import * as load_balancer_priority from './load-balancer-priority'; -import * as load_balancer_weighted_target from './load-balancer-weighted-target'; -import * as load_balancer_eds from './load-balancer-eds'; -import * as load_balancer_cds from './load-balancer-cds'; /** * A collection of functions associated with a channel that a load balancer @@ -101,23 +96,41 @@ export interface LoadBalancerConstructor { new (channelControlHelper: ChannelControlHelper): LoadBalancer; } +export interface LoadBalancingConfig { + getLoadBalancerName(): string; + toJsonObject(): object; +} + +export interface LoadBalancingConfigConstructor { + new(...args: any): LoadBalancingConfig; + createFromJson(obj: any): LoadBalancingConfig; +} + const registeredLoadBalancerTypes: { - [name: string]: LoadBalancerConstructor; + [name: string]: { + LoadBalancer: LoadBalancerConstructor, + LoadBalancingConfig: LoadBalancingConfigConstructor + }; } = {}; export function registerLoadBalancerType( typeName: string, - loadBalancerType: LoadBalancerConstructor + loadBalancerType: LoadBalancerConstructor, + loadBalancingConfigType: LoadBalancingConfigConstructor ) { - registeredLoadBalancerTypes[typeName] = loadBalancerType; + registeredLoadBalancerTypes[typeName] = { + LoadBalancer: loadBalancerType, + LoadBalancingConfig: loadBalancingConfigType + }; } export function createLoadBalancer( - typeName: string, + config: LoadBalancingConfig, channelControlHelper: ChannelControlHelper ): LoadBalancer | null { + const typeName = config.getLoadBalancerName(); if (typeName in registeredLoadBalancerTypes) { - return new registeredLoadBalancerTypes[typeName](channelControlHelper); + return new registeredLoadBalancerTypes[typeName].LoadBalancer(channelControlHelper); } else { return null; } @@ -127,22 +140,40 @@ export function isLoadBalancerNameRegistered(typeName: string): boolean { return typeName in registeredLoadBalancerTypes; } +export function getFirstUsableConfig(configs: LoadBalancingConfig[], defaultPickFirst?: true): LoadBalancingConfig; export function getFirstUsableConfig( - configs: LoadBalancingConfig[] + configs: LoadBalancingConfig[], + defaultPickFirst: boolean = false ): LoadBalancingConfig | null { for (const config of configs) { - if (config.name in registeredLoadBalancerTypes) { + if (config.getLoadBalancerName() in registeredLoadBalancerTypes) { return config; } } - return null; + if (defaultPickFirst) { + return new load_balancer_pick_first.PickFirstLoadBalancingConfig() + } else { + return null; + } +} + +export function validateLoadBalancingConfig(obj: any): LoadBalancingConfig { + if (!(obj !== null && (typeof obj === 'object'))) { + throw new Error('Load balancing config must be an object'); + } + const keys = Object.keys(obj); + if (keys.length !== 1) { + throw new Error('Provided load balancing config has multiple conflicting entries'); + } + const typeName = keys[0]; + if (typeName in registeredLoadBalancerTypes) { + return registeredLoadBalancerTypes[typeName].LoadBalancingConfig.createFromJson(obj[typeName]); + } else { + throw new Error(`Unrecognized load balancing config name ${typeName}`); + } } export function registerAll() { load_balancer_pick_first.setup(); load_balancer_round_robin.setup(); - load_balancer_priority.setup(); - load_balancer_weighted_target.setup(); - load_balancer_eds.setup(); - load_balancer_cds.setup(); } diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts deleted file mode 100644 index 92c4b2b9..00000000 --- a/packages/grpc-js/src/load-balancing-config.ts +++ /dev/null @@ -1,249 +0,0 @@ -/* - * 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. - * - */ - -/* This file is an implementation of gRFC A24: - * https://github.com/grpc/proposal/blob/master/A24-lb-policy-config.md. Each - * function here takes an object with unknown structure and returns its - * specific object type if the input has the right structure, and throws an - * error otherwise. */ - -/* The any type is purposely used here. All functions validate their input at - * runtime */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export type PickFirstConfig = {}; - -export type RoundRobinConfig = {}; - -export interface XdsConfig { - balancerName: string; - childPolicy: LoadBalancingConfig[]; - fallbackPolicy: LoadBalancingConfig[]; -} - -export interface GrpcLbConfig { - childPolicy: LoadBalancingConfig[]; -} - -export interface PriorityChild { - config: LoadBalancingConfig[]; -} - -export interface PriorityLbConfig { - children: Map; - priorities: string[]; -} - -export interface WeightedTarget { - weight: number; - child_policy: LoadBalancingConfig[]; -} - -export interface WeightedTargetLbConfig { - targets: Map; -} - -export interface EdsLbConfig { - cluster: string; - edsServiceName?: string; - lrsLoadReportingServerName?: string; - /** - * This policy's config is expected to be in the format used by the - * weighted_target policy. Defaults to weighted_target if not specified. - * - * This is currently not used because there is currently no other config - * that has the same format as weighted_target. - */ - localityPickingPolicy: LoadBalancingConfig[]; - /** - * Defaults to round_robin if not specified. - */ - endpointPickingPolicy: LoadBalancingConfig[]; -} - -export interface CdsLbConfig { - cluster: string; -} - -export interface PickFirstLoadBalancingConfig { - name: 'pick_first'; - pick_first: PickFirstConfig; -} - -export interface RoundRobinLoadBalancingConfig { - name: 'round_robin'; - round_robin: RoundRobinConfig; -} - -export interface XdsLoadBalancingConfig { - name: 'xds'; - xds: XdsConfig; -} - -export interface GrpcLbLoadBalancingConfig { - name: 'grpclb'; - grpclb: GrpcLbConfig; -} - -export interface PriorityLoadBalancingConfig { - name: 'priority'; - priority: PriorityLbConfig; -} - -export interface WeightedTargetLoadBalancingConfig { - name: 'weighted_target'; - weighted_target: WeightedTargetLbConfig; -} - -export interface EdsLoadBalancingConfig { - name: 'eds'; - eds: EdsLbConfig; -} - -export interface CdsLoadBalancingConfig { - name: 'cds'; - cds: CdsLbConfig; -} - -export type LoadBalancingConfig = - | PickFirstLoadBalancingConfig - | RoundRobinLoadBalancingConfig - | XdsLoadBalancingConfig - | GrpcLbLoadBalancingConfig - | PriorityLoadBalancingConfig - | WeightedTargetLoadBalancingConfig - | EdsLoadBalancingConfig - | CdsLoadBalancingConfig; - -export function isRoundRobinLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is RoundRobinLoadBalancingConfig { - return lbconfig.name === 'round_robin'; -} - -export function isXdsLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is XdsLoadBalancingConfig { - return lbconfig.name === 'xds'; -} - -export function isGrpcLbLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is GrpcLbLoadBalancingConfig { - return lbconfig.name === 'grpclb'; -} - -export function isPriorityLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is PriorityLoadBalancingConfig { - return lbconfig.name === 'priority'; -} - -export function isWeightedTargetLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is WeightedTargetLoadBalancingConfig { - return lbconfig.name === 'weighted_target'; -} - -export function isEdsLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is EdsLoadBalancingConfig { - return lbconfig.name === 'eds'; -} - -export function isCdsLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is CdsLoadBalancingConfig { - return lbconfig.name === 'cds'; -} - -/* In these functions we assume the input came from a JSON object. Therefore we - * expect that the prototype is uninteresting and that `in` can be used - * effectively */ - -function validateXdsConfig(xds: any): XdsConfig { - if (!('balancerName' in xds) || typeof xds.balancerName !== 'string') { - throw new Error('Invalid xds config: invalid balancerName'); - } - const xdsConfig: XdsConfig = { - balancerName: xds.balancerName, - childPolicy: [], - fallbackPolicy: [], - }; - if ('childPolicy' in xds) { - if (!Array.isArray(xds.childPolicy)) { - throw new Error('Invalid xds config: invalid childPolicy'); - } - for (const policy of xds.childPolicy) { - xdsConfig.childPolicy.push(validateConfig(policy)); - } - } - if ('fallbackPolicy' in xds) { - if (!Array.isArray(xds.fallbackPolicy)) { - throw new Error('Invalid xds config: invalid fallbackPolicy'); - } - for (const policy of xds.fallbackPolicy) { - xdsConfig.fallbackPolicy.push(validateConfig(policy)); - } - } - return xdsConfig; -} - -function validateGrpcLbConfig(grpclb: any): GrpcLbConfig { - const grpcLbConfig: GrpcLbConfig = { - childPolicy: [], - }; - if ('childPolicy' in grpclb) { - if (!Array.isArray(grpclb.childPolicy)) { - throw new Error('Invalid xds config: invalid childPolicy'); - } - for (const policy of grpclb.childPolicy) { - grpcLbConfig.childPolicy.push(validateConfig(policy)); - } - } - return grpcLbConfig; -} - -export function validateConfig(obj: any): LoadBalancingConfig { - if ('round_robin' in obj) { - if ('xds' in obj || 'grpclb' in obj) { - throw new Error('Multiple load balancing policies configured'); - } - if (obj['round_robin'] instanceof Object) { - return { - name: 'round_robin', - round_robin: {}, - }; - } - } - if ('xds' in obj) { - if ('grpclb' in obj) { - throw new Error('Multiple load balancing policies configured'); - } - return { - name: 'xds', - xds: validateXdsConfig(obj.xds), - }; - } - if ('grpclb' in obj) { - return { - name: 'grpclb', - grpclb: validateGrpcLbConfig(obj.grpclb), - }; - } - throw new Error('No recognized load balancing policy configured'); -} diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index 91b4e8f0..1140e8d8 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -20,20 +20,20 @@ import { LogVerbosity } from './constants'; let _logger: Partial = console; let _logVerbosity: LogVerbosity = LogVerbosity.ERROR; -if (process.env.GRPC_VERBOSITY) { - switch (process.env.GRPC_VERBOSITY) { - case 'DEBUG': - _logVerbosity = LogVerbosity.DEBUG; - break; - case 'INFO': - _logVerbosity = LogVerbosity.INFO; - break; - case 'ERROR': - _logVerbosity = LogVerbosity.ERROR; - break; - default: - // Ignore any other values - } +const verbosityString = process.env.GRPC_NODE_VERBOSITY ?? process.env.GRPC_VERBOSITY ?? ''; + +switch (verbosityString) { + case 'DEBUG': + _logVerbosity = LogVerbosity.DEBUG; + break; + case 'INFO': + _logVerbosity = LogVerbosity.INFO; + break; + case 'ERROR': + _logVerbosity = LogVerbosity.ERROR; + break; + default: + // Ignore any other values } export const getLogger = (): Partial => { @@ -55,9 +55,8 @@ export const log = (severity: LogVerbosity, ...args: any[]): void => { } }; -const enabledTracers = process.env.GRPC_TRACE - ? process.env.GRPC_TRACE.split(',') - : []; +const tracersString = process.env.GRPC_NODE_TRACE ?? process.env.GRPC_TRACE ?? ''; +const enabledTracers = tracersString.split(','); const allEnabled = enabledTracers.includes('all'); export function trace( diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 02ef91af..05f06b89 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -122,6 +122,9 @@ export function makeClientConstructor( } Object.keys(methods).forEach((name) => { + if (name === '__proto__') { + return; + } const attrs = methods[name]; let methodType: keyof typeof requesterFuncs; // TODO(murgatroid99): Verify that we don't need this anymore @@ -152,7 +155,7 @@ export function makeClientConstructor( ServiceClientImpl.prototype[name] = methodFunc; // Associate all provided attributes with the method Object.assign(ServiceClientImpl.prototype[name], attrs); - if (attrs.originalName) { + if (attrs.originalName && attrs.originalName !== '__proto__') { ServiceClientImpl.prototype[attrs.originalName] = ServiceClientImpl.prototype[name]; } @@ -201,6 +204,9 @@ export function loadPackageDefinition( if (Object.prototype.hasOwnProperty.call(packageDef, serviceFqn)) { const service = packageDef[serviceFqn]; const nameComponents = serviceFqn.split('.'); + if (nameComponents.some(comp => comp === '__proto__')) { + continue; + } const serviceName = nameComponents[nameComponents.length - 1]; let current = result; for (const packageName of nameComponents.slice(0, -1)) { diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index 42eeda82..184047b2 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -26,6 +26,7 @@ export enum PickResultType { COMPLETE, QUEUE, TRANSIENT_FAILURE, + DROP, } export interface PickResult { @@ -74,6 +75,14 @@ export interface TransientFailurePickResult extends PickResult { onCallStarted: null; } +export interface DropCallPickResult extends PickResult { + pickResultType: PickResultType.DROP; + subchannel: null; + status: StatusObject; + extraFilterFactory: null; + onCallStarted: null; +} + export interface PickArgs { metadata: Metadata; } diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 74e43ca0..2db8a5e4 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -31,6 +31,7 @@ import { LogVerbosity } from './constants'; import { SubchannelAddress, TcpSubchannelAddress } from './subchannel'; import { GrpcUri, uriToString, splitHostPort } from './uri-parser'; import { isIPv6, isIPv4 } from 'net'; +import { ChannelOptions } from './channel-options'; const TRACER_NAME = 'dns_resolver'; @@ -84,7 +85,11 @@ class DnsResolver implements Resolver { private latestServiceConfigError: StatusObject | null = null; private percentage: number; private defaultResolutionError: StatusObject; - constructor(private target: GrpcUri, private listener: ResolverListener) { + constructor( + private target: GrpcUri, + private listener: ResolverListener, + channelOptions: ChannelOptions + ) { trace('Resolver constructed for target ' + uriToString(target)); const hostPort = splitHostPort(target.path); if (hostPort === null) { diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts index 25856913..14bc0176 100644 --- a/packages/grpc-js/src/resolver-uds.ts +++ b/packages/grpc-js/src/resolver-uds.ts @@ -17,10 +17,15 @@ import { Resolver, ResolverListener, registerResolver } from './resolver'; import { SubchannelAddress } from './subchannel'; import { GrpcUri } from './uri-parser'; +import { ChannelOptions } from './channel-options'; class UdsResolver implements Resolver { private addresses: SubchannelAddress[] = []; - constructor(target: GrpcUri, private listener: ResolverListener) { + constructor( + target: GrpcUri, + private listener: ResolverListener, + channelOptions: ChannelOptions + ) { let path: string; if (target.authority === '') { path = '/' + target.path; diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 16c84351..57c750ae 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -21,6 +21,7 @@ import * as resolver_uds from './resolver-uds'; import { StatusObject } from './call-stream'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; +import { ChannelOptions } from './channel-options'; /** * A listener object passed to the resolver's constructor that provides name @@ -64,7 +65,11 @@ export interface Resolver { } export interface ResolverConstructor { - new (target: GrpcUri, listener: ResolverListener): Resolver; + new ( + target: GrpcUri, + listener: ResolverListener, + channelOptions: ChannelOptions + ): Resolver; /** * Get the default authority for a target. This loosely corresponds to that * target's hostname. Throws an error if this resolver class cannot parse the @@ -108,10 +113,11 @@ export function registerDefaultScheme(scheme: string) { */ export function createResolver( target: GrpcUri, - listener: ResolverListener + listener: ResolverListener, + options: ChannelOptions ): Resolver { if (target.scheme !== undefined && target.scheme in registeredResolvers) { - return new registeredResolvers[target.scheme](target, listener); + return new registeredResolvers[target.scheme](target, listener, options); } else { throw new Error( `No resolver could be created for target ${uriToString(target)}` diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index b467a767..2ce59d0c 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -19,13 +19,13 @@ import { ChannelControlHelper, LoadBalancer, getFirstUsableConfig, + LoadBalancingConfig } from './load-balancer'; -import { ServiceConfig } from './service-config'; +import { ServiceConfig, validateServiceConfig } from './service-config'; import { ConnectivityState } from './channel'; import { createResolver, Resolver } from './resolver'; import { ServiceError } from './call'; import { Picker, UnavailablePicker, QueuePicker } from './picker'; -import { LoadBalancingConfig } from './load-balancing-config'; import { BackoffTimeout } from './backoff-timeout'; import { Status } from './constants'; import { StatusObject } from './call-stream'; @@ -35,6 +35,8 @@ import { LogVerbosity } from './constants'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +import { ChannelOptions } from './channel-options'; +import { PickFirstLoadBalancingConfig } from './load-balancer-pick-first'; const TRACER_NAME = 'resolving_load_balancer'; @@ -57,6 +59,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { * This resolving load balancer's current connectivity state. */ private currentState: ConnectivityState = ConnectivityState.IDLE; + private readonly defaultServiceConfig: ServiceConfig; /** * The service config object from the last successful resolution, if * available. A value of null indicates that we have not yet received a valid @@ -90,8 +93,18 @@ export class ResolvingLoadBalancer implements LoadBalancer { constructor( private readonly target: GrpcUri, private readonly channelControlHelper: ChannelControlHelper, - private readonly defaultServiceConfig: ServiceConfig | null + private readonly channelOptions: ChannelOptions ) { + if (channelOptions['grpc.service_config']) { + this.defaultServiceConfig = validateServiceConfig( + JSON.parse(channelOptions['grpc.service_config']!) + ); + } else { + this.defaultServiceConfig = { + loadBalancingConfig: [], + methodConfig: [], + }; + } this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); this.childLoadBalancer = new ChildLoadBalancerHandler({ createSubchannel: channelControlHelper.createSubchannel.bind( @@ -114,68 +127,66 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.updateState(newState, picker); }, }); - this.innerResolver = createResolver(target, { - onSuccessfulResolution: ( - addressList: SubchannelAddress[], - serviceConfig: ServiceConfig | null, - serviceConfigError: ServiceError | null, - attributes: { [key: string]: unknown } - ) => { - let workingServiceConfig: ServiceConfig | null = null; - /* This first group of conditionals implements the algorithm described - * in https://github.com/grpc/proposal/blob/master/A21-service-config-error-handling.md - * in the section called "Behavior on receiving a new gRPC Config". - */ - if (serviceConfig === null) { - // Step 4 and 5 - if (serviceConfigError === null) { - // Step 5 - this.previousServiceConfig = null; - workingServiceConfig = this.defaultServiceConfig; - } else { - // Step 4 - if (this.previousServiceConfig === null) { - // Step 4.ii - this.handleResolutionFailure(serviceConfigError); + this.innerResolver = createResolver( + target, + { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: ServiceError | null, + attributes: { [key: string]: unknown } + ) => { + let workingServiceConfig: ServiceConfig | null = null; + /* This first group of conditionals implements the algorithm described + * in https://github.com/grpc/proposal/blob/master/A21-service-config-error-handling.md + * in the section called "Behavior on receiving a new gRPC Config". + */ + if (serviceConfig === null) { + // Step 4 and 5 + if (serviceConfigError === null) { + // Step 5 + this.previousServiceConfig = null; + workingServiceConfig = this.defaultServiceConfig; } else { - // Step 4.i - workingServiceConfig = this.previousServiceConfig; + // Step 4 + if (this.previousServiceConfig === null) { + // Step 4.ii + this.handleResolutionFailure(serviceConfigError); + } else { + // Step 4.i + workingServiceConfig = this.previousServiceConfig; + } } + } else { + // Step 3 + workingServiceConfig = serviceConfig; + this.previousServiceConfig = serviceConfig; } - } else { - // Step 3 - workingServiceConfig = serviceConfig; - this.previousServiceConfig = serviceConfig; - } - const workingConfigList = - workingServiceConfig?.loadBalancingConfig ?? []; - if (workingConfigList.length === 0) { - workingConfigList.push({ - name: 'pick_first', - pick_first: {}, - }); - } - const loadBalancingConfig = getFirstUsableConfig(workingConfigList); - if (loadBalancingConfig === null) { - // There were load balancing configs but none are supported. This counts as a resolution failure - this.handleResolutionFailure({ - code: Status.UNAVAILABLE, - details: - 'All load balancer options in service config are not compatible', - metadata: new Metadata(), - }); - return; - } - this.childLoadBalancer.updateAddressList( - addressList, - loadBalancingConfig, - attributes - ); + const workingConfigList = + workingServiceConfig?.loadBalancingConfig ?? []; + const loadBalancingConfig = getFirstUsableConfig(workingConfigList, true); + if (loadBalancingConfig === null) { + // There were load balancing configs but none are supported. This counts as a resolution failure + this.handleResolutionFailure({ + code: Status.UNAVAILABLE, + details: + 'All load balancer options in service config are not compatible', + metadata: new Metadata(), + }); + return; + } + this.childLoadBalancer.updateAddressList( + addressList, + loadBalancingConfig, + attributes + ); + }, + onError: (error: StatusObject) => { + this.handleResolutionFailure(error); + }, }, - onError: (error: StatusObject) => { - this.handleResolutionFailure(error); - }, - }); + channelOptions + ); this.backoffTimeout = new BackoffTimeout(() => { if (this.continueResolving) { diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 82d88517..aa8bd647 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -19,7 +19,7 @@ import { EventEmitter } from 'events'; import * as http2 from 'http2'; import { Duplex, Readable, Writable } from 'stream'; -import { StatusObject } from './call-stream'; +import { Deadline, StatusObject } from './call-stream'; import { Status, DEFAULT_MAX_SEND_MESSAGE_LENGTH, @@ -78,10 +78,11 @@ export type ServerSurfaceCall = { readonly metadata: Metadata; getPeer(): string; sendMetadata(responseMetadata: Metadata): void; + getDeadline(): Deadline; } & EventEmitter; export type ServerUnaryCall = ServerSurfaceCall & { - request: RequestType | null; + request: RequestType; }; export type ServerReadableStream< RequestType, @@ -91,33 +92,39 @@ export type ServerWritableStream< RequestType, ResponseType > = ServerSurfaceCall & - ObjectWritable & { request: RequestType | null }; + ObjectWritable & { + request: RequestType; + end: (metadata?: Metadata) => void; + }; export type ServerDuplexStream = ServerSurfaceCall & ObjectReadable & - ObjectWritable; + ObjectWritable & { end: (metadata?: Metadata) => void }; export class ServerUnaryCallImpl extends EventEmitter implements ServerUnaryCall { cancelled: boolean; - request: RequestType | null; constructor( private call: Http2ServerCallStream, - public metadata: Metadata + public metadata: Metadata, + public request: RequestType ) { super(); this.cancelled = false; - this.request = null; this.call.setupSurfaceCall(this); } getPeer(): string { - throw new Error('not implemented yet'); + return this.call.getPeer(); } sendMetadata(responseMetadata: Metadata): void { this.call.sendMetadata(responseMetadata); } + + getDeadline(): Deadline { + return this.call.getDeadline(); + } } export class ServerReadableStreamImpl @@ -145,29 +152,32 @@ export class ServerReadableStreamImpl } getPeer(): string { - throw new Error('not implemented yet'); + return this.call.getPeer(); } sendMetadata(responseMetadata: Metadata): void { this.call.sendMetadata(responseMetadata); } + + getDeadline(): Deadline { + return this.call.getDeadline(); + } } export class ServerWritableStreamImpl extends Writable implements ServerWritableStream { cancelled: boolean; - request: RequestType | null; private trailingMetadata: Metadata; constructor( private call: Http2ServerCallStream, public metadata: Metadata, - public serialize: Serialize + public serialize: Serialize, + public request: RequestType ) { super({ objectMode: true }); this.cancelled = false; - this.request = null; this.trailingMetadata = new Metadata(); this.call.setupSurfaceCall(this); @@ -178,13 +188,17 @@ export class ServerWritableStreamImpl } getPeer(): string { - throw new Error('not implemented yet'); + return this.call.getPeer(); } sendMetadata(responseMetadata: Metadata): void { this.call.sendMetadata(responseMetadata); } + getDeadline(): Deadline { + return this.call.getDeadline(); + } + _write( chunk: ResponseType, encoding: string, @@ -249,12 +263,25 @@ export class ServerDuplexStreamImpl extends Duplex } getPeer(): string { - throw new Error('not implemented yet'); + return this.call.getPeer(); } sendMetadata(responseMetadata: Metadata): void { this.call.sendMetadata(responseMetadata); } + + getDeadline(): Deadline { + return this.call.getDeadline(); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + end(metadata?: any) { + if (metadata) { + this.trailingMetadata = metadata; + } + + super.end(); + } } ServerDuplexStreamImpl.prototype._read = @@ -268,7 +295,7 @@ ServerDuplexStreamImpl.prototype.end = ServerWritableStreamImpl.prototype.end; // Unary response callback signature. export type sendUnaryData = ( error: ServerErrorResponse | ServerStatusResponse | null, - value: ResponseType | null, + value?: ResponseType | null, trailer?: Metadata, flags?: number ) => void; @@ -347,7 +374,8 @@ export class Http2ServerCallStream< ResponseType > extends EventEmitter { cancelled = false; - deadline: NodeJS.Timer = setTimeout(() => {}, 0); + deadlineTimer: NodeJS.Timer = setTimeout(() => {}, 0); + private deadline: Deadline = Infinity; private wantTrailers = false; private metadataSent = false; private canPush = false; @@ -373,6 +401,12 @@ export class Http2ServerCallStream< }); this.stream.once('close', () => { + trace( + 'Request to method ' + + this.handler?.path + + ' stream closed with rstCode ' + + this.stream.rstCode + ); this.cancelled = true; this.emit('cancelled', 'cancelled'); }); @@ -389,7 +423,7 @@ export class Http2ServerCallStream< } // Clear noop timer - clearTimeout(this.deadline); + clearTimeout(this.deadlineTimer); } private checkCancelled(): boolean { @@ -413,7 +447,7 @@ export class Http2ServerCallStream< this.metadataSent = true; const custom = customMetadata ? customMetadata.toHttp2Headers() : null; // TODO(cjihrig): Include compression headers. - const headers = Object.assign(defaultResponseHeaders, custom); + const headers = Object.assign({}, defaultResponseHeaders, custom); this.stream.respond(headers, defaultResponseOptions); } @@ -436,7 +470,9 @@ export class Http2ServerCallStream< const timeout = (+match[1] * deadlineUnitsToMs[match[2]]) | 0; - this.deadline = setTimeout(handleExpiredDeadline, timeout, this); + const now = new Date(); + this.deadline = now.setMilliseconds(now.getMilliseconds() + timeout); + this.deadlineTimer = setTimeout(handleExpiredDeadline, timeout, this); metadata.remove(GRPC_TIMEOUT_HEADER); } @@ -506,7 +542,7 @@ export class Http2ServerCallStream< async sendUnaryMessage( err: ServerErrorResponse | ServerStatusResponse | null, - value: ResponseType | null, + value?: ResponseType | null, metadata?: Metadata, flags?: number ) { @@ -550,7 +586,7 @@ export class Http2ServerCallStream< statusObj.details ); - clearTimeout(this.deadline); + clearTimeout(this.deadlineTimer); if (!this.wantTrailers) { this.wantTrailers = true; @@ -721,12 +757,24 @@ export class Http2ServerCallStream< } else { this.messagesToPush.push(deserialized); } - } catch (err) { + } catch (error) { // Ignore any remaining messages when errors occur. this.bufferedMessages.length = 0; - err.code = Status.INTERNAL; - readable.emit('error', err); + if ( + !( + 'code' in error && + typeof error.code === 'number' && + Number.isInteger(error.code) && + error.code >= Status.OK && + error.code <= Status.UNAUTHENTICATED + ) + ) { + // The error code is not a valid gRPC code so its being overwritten. + error.code = Status.INTERNAL; + } + + readable.emit('error', error); } this.isPushPending = false; @@ -738,6 +786,23 @@ export class Http2ServerCallStream< ); } } + + getPeer(): string { + const socket = this.stream.session.socket; + if (socket.remoteAddress) { + if (socket.remotePort) { + return `${socket.remoteAddress}:${socket.remotePort}`; + } else { + return socket.remoteAddress; + } + } else { + return 'unknown'; + } + } + + getDeadline(): Deadline { + return this.deadline; + } } /* eslint-disable @typescript-eslint/no-explicit-any */ diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index ebd4504d..335a11fc 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -148,10 +148,6 @@ export class Server { service: ServiceDefinition, implementation: UntypedServiceImplementation ): void { - if (this.started === true) { - throw new Error("Can't add a service to a started server."); - } - if ( service === null || typeof service !== 'object' || @@ -212,6 +208,21 @@ export class Server { }); } + removeService(service: ServiceDefinition): void { + if ( + service === null || + typeof service !== 'object' + ) { + throw new Error('removeService() requires object as argument'); + } + + const serviceKeys = Object.keys(service); + serviceKeys.forEach((name) => { + const attrs = service[name]; + this.unregister(attrs.path); + }); + } + bind(port: string, creds: ServerCredentials): void { throw new Error('Not implemented. Use bindAsync() instead'); } @@ -246,7 +257,9 @@ export class Server { throw new Error(`Could not get a default scheme for port "${port}"`); } - const serverOptions: http2.ServerOptions = {}; + const serverOptions: http2.ServerOptions = { + maxSendHeaderBlockLength: Number.MAX_SAFE_INTEGER + }; if ('grpc.max_concurrent_streams' in this.options) { serverOptions.settings = { maxConcurrentStreams: this.options['grpc.max_concurrent_streams'], @@ -415,7 +428,7 @@ export class Server { }, }; - const resolver = createResolver(portUri, resolverListener); + const resolver = createResolver(portUri, resolverListener, this.options); resolver.updateResolution(); } @@ -462,6 +475,10 @@ export class Server { return true; } + unregister(name: string): boolean { + return this.handlers.delete(name); + } + start(): void { if ( this.http2ServerList.length === 0 || @@ -543,11 +560,21 @@ export class Server { try { const path = headers[http2.constants.HTTP2_HEADER_PATH] as string; + const serverAddress = http2Server.address(); + let serverAddressString = 'null'; + if (serverAddress) { + if (typeof serverAddress === 'string') { + serverAddressString = serverAddress; + } else { + serverAddressString = + serverAddress.address + ':' + serverAddress.port; + } + } trace( 'Received call to method ' + path + ' at address ' + - http2Server.address()?.toString() + serverAddressString ); const handler = this.handlers.get(path); @@ -622,22 +649,23 @@ async function handleUnary( handler: UnaryHandler, metadata: Metadata ): Promise { - const emitter = new ServerUnaryCallImpl( - call, - metadata - ); const request = await call.receiveUnaryMessage(); if (request === undefined || call.cancelled) { return; } - emitter.request = request; + const emitter = new ServerUnaryCallImpl( + call, + metadata, + request + ); + handler.func( emitter, ( err: ServerErrorResponse | ServerStatusResponse | null, - value: ResponseType | null, + value?: ResponseType | null, trailer?: Metadata, flags?: number ) => { @@ -659,7 +687,7 @@ function handleClientStreaming( function respond( err: ServerErrorResponse | ServerStatusResponse | null, - value: ResponseType | null, + value?: ResponseType | null, trailer?: Metadata, flags?: number ) { @@ -689,10 +717,10 @@ async function handleServerStreaming( const stream = new ServerWritableStreamImpl( call, metadata, - handler.serialize + handler.serialize, + request ); - stream.request = request; handler.func(stream); } diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index ea5c449a..ed225e08 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -26,8 +26,8 @@ * runtime */ /* eslint-disable @typescript-eslint/no-explicit-any */ -import * as lbconfig from './load-balancing-config'; import * as os from 'os'; +import { LoadBalancingConfig, validateLoadBalancingConfig } from './load-balancer'; export interface MethodConfigName { service: string; @@ -44,7 +44,7 @@ export interface MethodConfig { export interface ServiceConfig { loadBalancingPolicy?: string; - loadBalancingConfig: lbconfig.LoadBalancingConfig[]; + loadBalancingConfig: LoadBalancingConfig[]; methodConfig: MethodConfig[]; } @@ -139,7 +139,7 @@ export function validateServiceConfig(obj: any): ServiceConfig { if ('loadBalancingConfig' in obj) { if (Array.isArray(obj.loadBalancingConfig)) { for (const config of obj.loadBalancingConfig) { - result.loadBalancingConfig.push(lbconfig.validateConfig(config)); + result.loadBalancingConfig.push(validateLoadBalancingConfig(config)); } } else { throw new Error('Invalid service config: invalid loadBalancingConfig'); diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index be72680e..c32ee43e 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -28,7 +28,7 @@ import * as logging from './logging'; import { LogVerbosity } from './constants'; import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; import * as net from 'net'; -import { GrpcUri, parseUri, splitHostPort } from './uri-parser'; +import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; import { ConnectionOptions } from 'tls'; import { FilterFactory, Filter } from './filter'; @@ -40,6 +40,10 @@ function trace(text: string): void { logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); } +function refTrace(text: string): void { + logging.trace(LogVerbosity.DEBUG, 'subchannel_refcount', text); +} + const MIN_CONNECT_TIMEOUT_MS = 20000; const INITIAL_BACKOFF_MS = 1000; const BACKOFF_MULTIPLIER = 1.6; @@ -176,6 +180,10 @@ export class Subchannel { * Timer reference tracking when the most recent ping will be considered lost */ private keepaliveTimeoutId: NodeJS.Timer; + /** + * Indicates whether keepalive pings should be sent without any active calls + */ + private keepaliveWithoutCalls: boolean = false; /** * Tracks calls with references to this subchannel @@ -222,6 +230,11 @@ export class Subchannel { if ('grpc.keepalive_timeout_ms' in options) { this.keepaliveTimeoutMs = options['grpc.keepalive_timeout_ms']!; } + if ('grpc.keepalive_permit_without_calls' in options) { + this.keepaliveWithoutCalls = options['grpc.keepalive_permit_without_calls'] === 1; + } else { + this.keepaliveWithoutCalls = false; + } this.keepaliveIntervalId = setTimeout(() => {}, 0); clearTimeout(this.keepaliveIntervalId); this.keepaliveTimeoutId = setTimeout(() => {}, 0); @@ -263,6 +276,7 @@ export class Subchannel { } private sendPing() { + logging.trace(LogVerbosity.DEBUG, 'keepalive', 'Sending ping to ' + this.subchannelAddressString); this.keepaliveTimeoutId = setTimeout(() => { this.transitionToState([ConnectivityState.READY], ConnectivityState.IDLE); }, this.keepaliveTimeoutMs); @@ -277,7 +291,8 @@ export class Subchannel { this.keepaliveIntervalId = setInterval(() => { this.sendPing(); }, this.keepaliveTimeMs); - this.sendPing(); + /* Don't send a ping immediately because whatever caused us to start + * sending pings should also involve some network activity. */ } private stopKeepalivePings() { @@ -291,6 +306,7 @@ export class Subchannel { ); let connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; + connectionOptions.maxSendHeaderBlockLength = Number.MAX_SAFE_INTEGER; let addressScheme = 'http://'; if ('secureContext' in connectionOptions) { addressScheme = 'https://'; @@ -405,17 +421,17 @@ export class Subchannel { errorCode === http2.constants.NGHTTP2_ENHANCE_YOUR_CALM && opaqueData.equals(tooManyPingsData) ) { - logging.log( - LogVerbosity.ERROR, - `Connection to ${this.channelTarget} rejected by server because of excess pings` - ); this.keepaliveTimeMs = Math.min( 2 * this.keepaliveTimeMs, KEEPALIVE_MAX_TIME_MS ); + logging.log( + LogVerbosity.ERROR, + `Connection to ${uriToString(this.channelTarget)} at ${this.subchannelAddressString} rejected by server because of excess pings. Increasing ping interval to ${this.keepaliveTimeMs} ms` + ); } trace( - this.subchannelAddress + + this.subchannelAddressString + ' connection closed by GOAWAY with code ' + errorCode ); @@ -467,11 +483,13 @@ export class Subchannel { * if a connection is successfully established through the proxy. * If the proxy is not used, these connectionOptions are discarded * anyway */ - connectionOptions.servername = getDefaultAuthority( + const targetPath = getDefaultAuthority( parseUri(this.options['grpc.http_connect_target'] as string) ?? { path: 'localhost', } ); + const hostPort = splitHostPort(targetPath); + connectionOptions.servername = hostPort?.host ?? targetPath; } } } @@ -524,6 +542,9 @@ export class Subchannel { listener(); } }); + if (this.keepaliveWithoutCalls) { + this.startKeepalivePings(); + } break; case ConnectivityState.CONNECTING: this.startBackoff(); @@ -583,7 +604,7 @@ export class Subchannel { } callRef() { - trace( + refTrace( this.subchannelAddressString + ' callRefcount ' + this.callRefcount + @@ -594,13 +615,15 @@ export class Subchannel { if (this.session) { this.session.ref(); } - this.startKeepalivePings(); + if (!this.keepaliveWithoutCalls) { + this.startKeepalivePings(); + } } this.callRefcount += 1; } callUnref() { - trace( + refTrace( this.subchannelAddressString + ' callRefcount ' + this.callRefcount + @@ -612,13 +635,15 @@ export class Subchannel { if (this.session) { this.session.unref(); } - this.stopKeepalivePings(); + if (!this.keepaliveWithoutCalls) { + this.stopKeepalivePings(); + } this.checkBothRefcounts(); } } ref() { - trace( + refTrace( this.subchannelAddressString + ' refcount ' + this.refcount + @@ -629,7 +654,7 @@ export class Subchannel { } unref() { - trace( + refTrace( this.subchannelAddressString + ' refcount ' + this.refcount + @@ -689,7 +714,7 @@ export class Subchannel { for (const header of Object.keys(headers)) { headersString += '\t\t' + header + ': ' + headers[header] + '\n'; } - trace('Starting stream with headers\n' + headersString); + logging.trace(LogVerbosity.DEBUG, 'call_stream', 'Starting stream on subchannel ' + this.subchannelAddressString + ' with headers\n' + headersString); callStream.attachHttp2Stream(http2Stream, this, extraFilterFactory); } diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts deleted file mode 100644 index 98bafda3..00000000 --- a/packages/grpc-js/src/xds-client.ts +++ /dev/null @@ -1,561 +0,0 @@ -/* - * Copyright 2020 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. - * - */ - -import * as protoLoader from '@grpc/proto-loader'; -import { loadPackageDefinition } from './make-client'; -import * as adsTypes from './generated/ads'; -import { createGoogleDefaultCredentials } from './channel-credentials'; -import { loadBootstrapInfo } from './xds-bootstrap'; -import { ClientDuplexStream, ServiceError } from './call'; -import { StatusObject } from './call-stream'; -import { isIPv4, isIPv6 } from 'net'; -import { Status, LogVerbosity } from './constants'; -import { Metadata } from './metadata'; -import * as logging from './logging'; -import { ServiceConfig } from './service-config'; -import { ChannelOptions } from './channel-options'; -import { Node } from './generated/envoy/api/v2/core/Node'; -import { AggregatedDiscoveryServiceClient } from './generated/envoy/service/discovery/v2/AggregatedDiscoveryService'; -import { DiscoveryRequest } from './generated/envoy/api/v2/DiscoveryRequest'; -import { DiscoveryResponse__Output } from './generated/envoy/api/v2/DiscoveryResponse'; -import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; -import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; - -const TRACER_NAME = 'xds_client'; - -function trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); -} - -const clientVersion = require('../../package.json').version; - -const EDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; -const CDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Cluster'; - -let loadedProtos: Promise | null = null; - -function loadAdsProtos(): Promise { - if (loadedProtos !== null) { - return loadedProtos; - } - loadedProtos = protoLoader - .load( - [ - 'envoy/service/discovery/v2/ads.proto', - 'envoy/api/v2/listener.proto', - 'envoy/api/v2/route.proto', - 'envoy/api/v2/cluster.proto', - 'envoy/api/v2/endpoint.proto', - ], - { - keepCase: true, - longs: String, - enums: String, - defaults: true, - oneofs: true, - includeDirs: [ - // Paths are relative to src/build - __dirname + '/../../deps/envoy-api/', - __dirname + '/../../deps/udpa/', - __dirname + '/../../deps/googleapis/', - __dirname + '/../../deps/protoc-gen-validate/', - ], - } - ) - .then( - (packageDefinition) => - (loadPackageDefinition( - packageDefinition - ) as unknown) as adsTypes.ProtoGrpcType - ); - return loadedProtos; -} - -export interface Watcher { - onValidUpdate(update: UpdateType): void; - onTransientError(error: StatusObject): void; - onResourceDoesNotExist(): void; -} - -export class XdsClient { - private node: Node | null = null; - private client: AggregatedDiscoveryServiceClient | null = null; - private adsCall: ClientDuplexStream< - DiscoveryRequest, - DiscoveryResponse__Output - > | null = null; - - private hasShutdown = false; - - private endpointWatchers: Map< - string, - Watcher[] - > = new Map[]>(); - private lastEdsVersionInfo = ''; - private lastEdsNonce = ''; - private latestEdsResponses: ClusterLoadAssignment__Output[] = []; - - private clusterWatchers: Map[]> = new Map< - string, - Watcher[] - >(); - private lastCdsVersionInfo = ''; - private lastCdsNonce = ''; - private latestCdsResponses: Cluster__Output[] = []; - - constructor( - private targetName: string, - private serviceConfigWatcher: Watcher, - channelOptions: ChannelOptions - ) { - const channelArgs = { ...channelOptions }; - const channelArgsToRemove = [ - /* The SSL target name override corresponds to the target, and this - * client has its own target */ - 'grpc.ssl_target_name_override', - /* The default authority also corresponds to the target */ - 'grpc.default_authority', - /* This client will have its own specific keepalive time setting */ - 'grpc.keepalive_time_ms', - /* The service config specifies the load balancing policy. This channel - * needs its own separate load balancing policy setting. In particular, - * recursively using an xDS load balancer for the xDS client would be - * bad */ - 'grpc.service_config', - ]; - for (const arg of channelArgsToRemove) { - delete channelArgs[arg]; - } - channelArgs['grpc.keepalive_time_ms'] = 5000; - Promise.all([loadBootstrapInfo(), loadAdsProtos()]).then( - ([bootstrapInfo, protoDefinitions]) => { - if (this.hasShutdown) { - return; - } - this.node = { - ...bootstrapInfo.node, - build_version: `gRPC Node Pure JS ${clientVersion}`, - user_agent_name: 'gRPC Node Pure JS', - }; - this.client = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( - bootstrapInfo.xdsServers[0].serverUri, - createGoogleDefaultCredentials(), - channelArgs - ); - this.maybeStartAdsStream(); - }, - (error) => { - trace('Failed to initialize xDS Client. ' + error.message); - // Bubble this error up to any listeners - this.reportStreamError({ - code: Status.INTERNAL, - details: `Failed to initialize xDS Client. ${error.message}`, - metadata: new Metadata(), - }); - } - ); - } - - /** - * Start the ADS stream if the client exists and there is not already an - * existing stream, and there - */ - private maybeStartAdsStream() { - if (this.client === null) { - return; - } - if (this.adsCall !== null) { - return; - } - if (this.hasShutdown) { - return; - } - this.adsCall = this.client.StreamAggregatedResources(); - this.adsCall.on('data', (message: DiscoveryResponse__Output) => { - switch (message.type_url) { - case EDS_TYPE_URL: { - const edsResponses: ClusterLoadAssignment__Output[] = []; - for (const resource of message.resources) { - if ( - protoLoader.isAnyExtension(resource) && - resource['@type'] === EDS_TYPE_URL - ) { - const resp = resource as protoLoader.AnyExtension & - ClusterLoadAssignment__Output; - if (!this.validateEdsResponse(resp)) { - this.nackEds('ClusterLoadAssignment validation failed'); - return; - } - edsResponses.push(resp); - } else { - this.nackEds( - `Invalid resource type ${ - protoLoader.isAnyExtension(resource) - ? resource['@type'] - : resource.type_url - }` - ); - return; - } - } - for (const message of edsResponses) { - this.handleEdsResponse(message); - } - this.lastEdsVersionInfo = message.version_info; - this.lastEdsNonce = message.nonce; - this.latestEdsResponses = edsResponses; - this.ackEds(); - break; - } - case CDS_TYPE_URL: { - const cdsResponses: Cluster__Output[] = []; - for (const resource of message.resources) { - if ( - protoLoader.isAnyExtension(resource) && - resource['@type'] === CDS_TYPE_URL - ) { - const resp = resource as protoLoader.AnyExtension & - Cluster__Output; - if (!this.validateCdsResponse(resp)) { - this.nackCds('Cluster validation failed'); - return; - } - } else { - this.nackEds( - `Invalid resource type ${ - protoLoader.isAnyExtension(resource) - ? resource['@type'] - : resource.type_url - }` - ); - return; - } - } - for (const message of cdsResponses) { - this.handleCdsResponse(message); - } - this.lastCdsVersionInfo = message.version_info; - this.lastCdsNonce = message.nonce; - this.latestCdsResponses = cdsResponses; - this.ackCds(); - break; - } - default: - this.nackUnknown( - message.type_url, - message.version_info, - message.nonce - ); - } - }); - this.adsCall.on('error', (error: ServiceError) => { - trace( - 'ADS stream ended. code=' + error.code + ' details= ' + error.details - ); - this.adsCall = null; - this.reportStreamError(error); - /* Connection backoff is handled by the client object, so we can - * immediately start a new request to indicate that it should try to - * reconnect */ - this.maybeStartAdsStream(); - }); - const endpointWatcherNames = Array.from(this.endpointWatchers.keys()); - if (endpointWatcherNames.length > 0) { - this.adsCall.write({ - node: this.node!, - type_url: EDS_TYPE_URL, - resource_names: endpointWatcherNames, - }); - } - } - - private nackUnknown(typeUrl: string, versionInfo: string, nonce: string) { - if (!this.adsCall) { - return; - } - this.adsCall.write({ - node: this.node!, - type_url: typeUrl, - version_info: versionInfo, - response_nonce: nonce, - error_detail: { - message: `Unknown type_url ${typeUrl}`, - }, - }); - } - - /** - * Acknowledge an EDS update. This should be called after the local nonce and - * version info are updated so that it sends the post-update values. - */ - private ackEds() { - if (!this.adsCall) { - return; - } - this.adsCall.write({ - node: this.node!, - type_url: EDS_TYPE_URL, - resource_names: Array.from(this.endpointWatchers.keys()), - response_nonce: this.lastEdsNonce, - version_info: this.lastEdsVersionInfo, - }); - } - - private ackCds() { - if (!this.adsCall) { - return; - } - this.adsCall.write({ - node: this.node!, - type_url: CDS_TYPE_URL, - resource_names: Array.from(this.clusterWatchers.keys()), - response_nonce: this.lastCdsNonce, - version_info: this.lastCdsVersionInfo, - }); - } - - /** - * Reject an EDS update. This should be called without updating the local - * nonce and version info. - */ - private nackEds(message: string) { - if (!this.adsCall) { - return; - } - this.adsCall.write({ - node: this.node!, - type_url: EDS_TYPE_URL, - resource_names: Array.from(this.endpointWatchers.keys()), - response_nonce: this.lastEdsNonce, - version_info: this.lastEdsVersionInfo, - error_detail: { - message, - }, - }); - } - - private nackCds(message: string) { - if (!this.adsCall) { - return; - } - this.adsCall.write({ - node: this.node!, - type_url: CDS_TYPE_URL, - resource_names: Array.from(this.clusterWatchers.keys()), - response_nonce: this.lastCdsNonce, - version_info: this.lastCdsVersionInfo, - error_detail: { - message, - }, - }); - } - - /** - * Validate the ClusterLoadAssignment object by these rules: - * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto - * @param message - */ - private validateEdsResponse(message: ClusterLoadAssignment__Output): boolean { - for (const endpoint of message.endpoints) { - for (const lb of endpoint.lb_endpoints) { - const socketAddress = lb.endpoint?.address?.socket_address; - if (!socketAddress) { - return false; - } - if (socketAddress.port_specifier !== 'port_value') { - return false; - } - if (!(isIPv4(socketAddress.address) || isIPv6(socketAddress.address))) { - return false; - } - } - } - return true; - } - - private validateCdsResponse(message: Cluster__Output): boolean { - if (message.type !== 'EDS') { - return false; - } - if (!message.eds_cluster_config?.eds_config?.ads) { - return false; - } - if (message.lb_policy !== 'ROUND_ROBIN') { - return false; - } - if (message.lrs_server) { - if (!message.lrs_server.self) { - return false; - } - } - return true; - } - - private handleEdsResponse(message: ClusterLoadAssignment__Output) { - const watchers = this.endpointWatchers.get(message.cluster_name) ?? []; - for (const watcher of watchers) { - watcher.onValidUpdate(message); - } - } - - private handleCdsResponse(message: Cluster__Output) { - const watchers = this.clusterWatchers.get(message.name) ?? []; - for (const watcher of watchers) { - watcher.onValidUpdate(message); - } - } - - private updateEdsNames() { - if (this.adsCall) { - this.adsCall.write({ - node: this.node!, - type_url: EDS_TYPE_URL, - resource_names: Array.from(this.endpointWatchers.keys()), - response_nonce: this.lastEdsNonce, - version_info: this.lastEdsVersionInfo, - }); - } - } - - private updateCdsNames() { - if (this.adsCall) { - this.adsCall.write({ - node: this.node!, - type_url: CDS_TYPE_URL, - resource_names: Array.from(this.clusterWatchers.keys()), - response_nonce: this.lastCdsNonce, - version_info: this.lastCdsVersionInfo, - }); - } - } - - private reportStreamError(status: StatusObject) { - for (const watcherList of [ - ...this.endpointWatchers.values(), - ...this.clusterWatchers.values(), - ]) { - for (const watcher of watcherList) { - watcher.onTransientError(status); - } - } - // Also do the same for other types of watchers when those are implemented - } - - addEndpointWatcher( - edsServiceName: string, - watcher: Watcher - ) { - trace('Watcher added for endpoint ' + edsServiceName); - let watchersEntry = this.endpointWatchers.get(edsServiceName); - let addedServiceName = false; - if (watchersEntry === undefined) { - addedServiceName = true; - watchersEntry = []; - this.endpointWatchers.set(edsServiceName, watchersEntry); - } - watchersEntry.push(watcher); - if (addedServiceName) { - this.updateEdsNames(); - } - - /* If we have already received an update for the requested edsServiceName, - * immediately pass that update along to the watcher */ - for (const message of this.latestEdsResponses) { - if (message.cluster_name === edsServiceName) { - /* These updates normally occur asynchronously, so we ensure that - * the same happens here */ - process.nextTick(() => { - watcher.onValidUpdate(message); - }); - } - } - } - - removeEndpointWatcher( - edsServiceName: string, - watcher: Watcher - ) { - trace('Watcher removed for endpoint ' + edsServiceName); - const watchersEntry = this.endpointWatchers.get(edsServiceName); - let removedServiceName = false; - if (watchersEntry !== undefined) { - const entryIndex = watchersEntry.indexOf(watcher); - if (entryIndex >= 0) { - watchersEntry.splice(entryIndex, 1); - } - if (watchersEntry.length === 0) { - removedServiceName = true; - this.endpointWatchers.delete(edsServiceName); - } - } - if (removedServiceName) { - this.updateEdsNames(); - } - } - - addClusterWatcher(clusterName: string, watcher: Watcher) { - trace('Watcher added for cluster ' + clusterName); - let watchersEntry = this.clusterWatchers.get(clusterName); - let addedServiceName = false; - if (watchersEntry === undefined) { - addedServiceName = true; - watchersEntry = []; - this.clusterWatchers.set(clusterName, watchersEntry); - } - watchersEntry.push(watcher); - if (addedServiceName) { - this.updateCdsNames(); - } - - /* If we have already received an update for the requested clusterName, - * immediately pass that update along to the watcher */ - for (const message of this.latestCdsResponses) { - if (message.name === clusterName) { - /* These updates normally occur asynchronously, so we ensure that - * the same happens here */ - process.nextTick(() => { - watcher.onValidUpdate(message); - }); - } - } - } - - removeClusterWatcher(clusterName: string, watcher: Watcher) { - trace('Watcher removed for endpoint ' + clusterName); - const watchersEntry = this.clusterWatchers.get(clusterName); - let removedServiceName = false; - if (watchersEntry !== undefined) { - const entryIndex = watchersEntry.indexOf(watcher); - if (entryIndex >= 0) { - watchersEntry.splice(entryIndex, 1); - } - if (watchersEntry.length === 0) { - removedServiceName = true; - this.endpointWatchers.delete(clusterName); - } - } - if (removedServiceName) { - this.updateCdsNames(); - } - } - - shutdown(): void { - this.adsCall?.cancel(); - this.client?.close(); - this.hasShutdown = true; - } -} diff --git a/packages/grpc-js/test/test-call-propagation.ts b/packages/grpc-js/test/test-call-propagation.ts new file mode 100644 index 00000000..3ce57be1 --- /dev/null +++ b/packages/grpc-js/test/test-call-propagation.ts @@ -0,0 +1,253 @@ +/* + * Copyright 2020 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. + * + */ + +import * as assert from 'assert'; + +import * as grpc from '../src'; +import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; + +import { loadProtoFile } from './common'; + +function multiDone(done: () => void, target: number) { + let count = 0; + return () => { + count++; + if (count >= target) { + done(); + } + } +} + +describe('Call propagation', () => { + let server: grpc.Server; + let Client: ServiceClientConstructor; + let client: ServiceClient; + let proxyServer: grpc.Server; + let proxyClient: ServiceClient; + + before((done) => { + Client = loadProtoFile(__dirname + '/fixtures/test_service.proto').TestService as ServiceClientConstructor; + server = new grpc.Server(); + server.addService(Client.service, { + unary: () => {}, + clientStream: () => {}, + serverStream: () => {}, + bidiStream: () => {} + }); + proxyServer = new grpc.Server(); + server.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { + if (error) { + done(error); + return; + } + server.start(); + client = new Client(`localhost:${port}`, grpc.credentials.createInsecure()); + proxyServer.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, proxyPort) => { + if (error) { + done(error); + return; + } + proxyServer.start(); + proxyClient = new Client(`localhost:${proxyPort}`, grpc.credentials.createInsecure()); + done(); + }); + }); + }); + afterEach(() => { + proxyServer.removeService(Client.service); + }); + after(() => { + server.forceShutdown(); + proxyServer.forceShutdown(); + }); + describe('Cancellation', () => { + it('should work with unary requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientUnaryCall; + proxyServer.addService(Client.service, { + unary: (parent: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => { + client.unary(parent.request, {parent: parent}, (error: grpc.ServiceError, value: unknown) => { + callback(error, value); + assert(error); + assert.strictEqual(error.code, grpc.status.CANCELLED); + done(); + }); + /* Cancel the original call after the server starts processing it to + * ensure that it does reach the server. */ + call.cancel(); + } + }); + call = proxyClient.unary({}, (error: grpc.ServiceError, value: unknown) => { + assert(error); + assert.strictEqual(error.code, grpc.status.CANCELLED); + done(); + }); + }); + it('Should work with client streaming requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientWritableStream; + proxyServer.addService(Client.service, { + clientStream: (parent: grpc.ServerReadableStream, callback: grpc.sendUnaryData) => { + client.clientStream({parent: parent}, (error: grpc.ServiceError, value: unknown) => { + callback(error, value); + assert(error); + assert.strictEqual(error.code, grpc.status.CANCELLED); + done(); + }); + /* Cancel the original call after the server starts processing it to + * ensure that it does reach the server. */ + call.cancel(); + } + }); + call = proxyClient.clientStream((error: grpc.ServiceError, value: unknown) => { + assert(error); + assert.strictEqual(error.code, grpc.status.CANCELLED); + done(); + }); + }); + it('Should work with server streaming requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientReadableStream; + proxyServer.addService(Client.service, { + serverStream: (parent: grpc.ServerWritableStream) => { + const child = client.serverStream(parent.request, {parent: parent}); + child.on('error', () => {}); + child.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); + } + }); + call = proxyClient.serverStream({}); + call.on('error', () => {}); + call.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.CANCELLED); + done(); + }); + }); + it('Should work with bidi streaming requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientDuplexStream; + proxyServer.addService(Client.service, { + bidiStream: (parent: grpc.ServerDuplexStream) => { + const child = client.bidiStream({parent: parent}); + child.on('error', () => {}); + child.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); + } + }); + call = proxyClient.bidiStream(); + call.on('error', () => {}); + call.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.CANCELLED); + done(); + }); + }); + }); + describe('Deadlines', () => { + it('should work with unary requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientUnaryCall; + proxyServer.addService(Client.service, { + unary: (parent: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => { + client.unary(parent.request, {parent: parent, propagate_flags: grpc.propagate.DEADLINE}, (error: grpc.ServiceError, value: unknown) => { + callback(error, value); + assert(error); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + } + }); + const deadline = new Date(); + deadline.setMilliseconds(deadline.getMilliseconds() + 100); + call = proxyClient.unary({}, {deadline}, (error: grpc.ServiceError, value: unknown) => { + assert(error); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + }); + it('Should work with client streaming requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientWritableStream; + proxyServer.addService(Client.service, { + clientStream: (parent: grpc.ServerReadableStream, callback: grpc.sendUnaryData) => { + client.clientStream({parent: parent, propagate_flags: grpc.propagate.DEADLINE}, (error: grpc.ServiceError, value: unknown) => { + callback(error, value); + assert(error); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + } + }); + const deadline = new Date(); + deadline.setMilliseconds(deadline.getMilliseconds() + 100); + call = proxyClient.clientStream({deadline, propagate_flags: grpc.propagate.DEADLINE}, (error: grpc.ServiceError, value: unknown) => { + assert(error); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + }); + it('Should work with server streaming requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientReadableStream; + proxyServer.addService(Client.service, { + serverStream: (parent: grpc.ServerWritableStream) => { + const child = client.serverStream(parent.request, {parent: parent, propagate_flags: grpc.propagate.DEADLINE}); + child.on('error', () => {}); + child.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + } + }); + const deadline = new Date(); + deadline.setMilliseconds(deadline.getMilliseconds() + 100); + call = proxyClient.serverStream({}, {deadline}); + call.on('error', () => {}); + call.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + }); + it('Should work with bidi streaming requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientDuplexStream; + proxyServer.addService(Client.service, { + bidiStream: (parent: grpc.ServerDuplexStream) => { + const child = client.bidiStream({parent: parent, propagate_flags: grpc.propagate.DEADLINE}); + child.on('error', () => {}); + child.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + } + }); + const deadline = new Date(); + deadline.setMilliseconds(deadline.getMilliseconds() + 100); + call = proxyClient.bidiStream({deadline}); + call.on('error', () => {}); + call.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + }); + }); +}); \ No newline at end of file diff --git a/packages/grpc-js/test/test-prototype-pollution.ts b/packages/grpc-js/test/test-prototype-pollution.ts new file mode 100644 index 00000000..12092608 --- /dev/null +++ b/packages/grpc-js/test/test-prototype-pollution.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2020 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. + * + */ + +import * as assert from 'assert'; + +import { loadPackageDefinition } from '../src'; + +describe('loadPackageDefinition', () => { + it('Should not allow prototype pollution', () => { + loadPackageDefinition({'__proto__.polluted': true} as any); + assert.notStrictEqual(({} as any).polluted, true); + }); +}); diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index d2a85fc4..42ca64d4 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -63,7 +63,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should default to port 443', done => { @@ -98,7 +98,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should correctly represent an ipv4 address', done => { @@ -125,7 +125,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should correctly represent an ipv6 address', done => { @@ -152,7 +152,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should correctly represent a bracketed ipv6 address', done => { @@ -179,7 +179,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should resolve a public address', done => { @@ -199,7 +199,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should resolve a name with multiple dots', done => { @@ -226,7 +226,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); /* TODO(murgatroid99): re-enable this test, once we can get the IPv6 result @@ -255,7 +255,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should resolve a DNS name to IPv4 and IPv6 addresses', done => { @@ -284,7 +284,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should resolve a name with a hyphen', done => { @@ -306,7 +306,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should resolve gRPC interop servers', done => { @@ -331,9 +331,9 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver1 = resolverManager.createResolver(target1, listener); + const resolver1 = resolverManager.createResolver(target1, listener, {}); resolver1.updateResolution(); - const resolver2 = resolverManager.createResolver(target2, listener); + const resolver2 = resolverManager.createResolver(target2, listener, {}); resolver2.updateResolution(); }); }); @@ -359,7 +359,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should handle an absolute Unix Domain Socket name', done => { @@ -384,7 +384,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); }); diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 434efbbc..58b10288 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -202,7 +202,7 @@ describe('Server', () => { }); }); - it('fails if the server has been started', done => { + it('succeeds after server has been started', done => { const server = new Server(); server.bindAsync( @@ -211,15 +211,131 @@ describe('Server', () => { (err, port) => { assert.ifError(err); server.start(); - assert.throws(() => { + assert.doesNotThrow(() => { server.addService(mathServiceAttrs, dummyImpls); - }, /Can't add a service to a started server\./); + }); server.tryShutdown(done); } ); }); }); + describe('removeService', () => { + let server: Server; + let client: ServiceClient; + + const mathProtoFile = path.join(__dirname, 'fixtures', 'math.proto'); + const mathClient = (loadProtoFile(mathProtoFile).math as any).Math; + const mathServiceAttrs = mathClient.service; + const dummyImpls = { div() {}, divMany() {}, fib() {}, sum() {} }; + + beforeEach(done => { + server = new Server(); + server.addService(mathServiceAttrs, dummyImpls); + server.bindAsync( + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + client = new mathClient( + `localhost:${port}`, + grpc.credentials.createInsecure() + ); + server.start(); + done(); + } + ); + }); + + afterEach(done => { + client.close(); + server.tryShutdown(done); + }); + + it('succeeds with a single service by removing all method handlers', done => { + server.removeService(mathServiceAttrs); + + let methodsVerifiedCount = 0; + const methodsToVerify = Object.keys(mathServiceAttrs); + + const assertFailsWithUnimplementedError = (error: ServiceError) => { + assert(error); + assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + methodsVerifiedCount++; + if (methodsVerifiedCount === methodsToVerify.length) { + done(); + } + }; + + methodsToVerify.forEach((method) => { + const call = client[method]({}, assertFailsWithUnimplementedError); // for unary + call.on('error', assertFailsWithUnimplementedError); // for streamed + }); + }); + + it('fails for non-object service definition argument', () => { + assert.throws(() => { + server.removeService('upsie' as any) + }, /removeService.*requires object as argument/ + ); + }); + }); + + describe('unregister', () => { + + let server: Server; + let client: ServiceClient; + + const mathProtoFile = path.join(__dirname, 'fixtures', 'math.proto'); + const mathClient = (loadProtoFile(mathProtoFile).math as any).Math; + const mathServiceAttrs = mathClient.service; + + beforeEach(done => { + server = new Server(); + server.addService(mathServiceAttrs, { + div(call: ServerUnaryCall, callback: sendUnaryData) { + callback(null, {quotient: '42'}); + }, + }); + server.bindAsync( + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + client = new mathClient( + `localhost:${port}`, + grpc.credentials.createInsecure() + ); + server.start(); + done(); + } + ); + }); + + afterEach(done => { + client.close(); + server.tryShutdown(done); + }); + + it('removes handler by name and returns true', done => { + const name = mathServiceAttrs['Div'].path; + assert.strictEqual(server.unregister(name), true, 'Server#unregister should return true on success'); + + client.div( + { divisor: 4, dividend: 3 }, + (error: ServiceError, response: any) => { + assert(error); + assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + done(); + } + ); + }); + + it('returns false for unknown handler', () => { + assert.strictEqual(server.unregister('noOneHere'), false, 'Server#unregister should return false on failure'); + }); + }); + it('throws when unimplemented methods are called', () => { const server = new Server(); diff --git a/packages/grpc-tools/deps/protobuf b/packages/grpc-tools/deps/protobuf index d0bfd522..2514f0bd 160000 --- a/packages/grpc-tools/deps/protobuf +++ b/packages/grpc-tools/deps/protobuf @@ -1 +1 @@ -Subproject commit d0bfd5221182da1a7cc280f3337b5e41a89539cf +Subproject commit 2514f0bd7da7e2af1bed4c5d1b84f031c4d12c10 diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 7dddbff0..86f45dc3 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.9.1", + "version": "1.10.0", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 67130e03..f8db35b3 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -76,13 +76,15 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio const options = { 'grpc.ssl_target_name_override': 'foo.test.google.fr', 'grpc.default_authority': 'foo.test.google.fr', - 'grpc.max_send_message_length': 4*1024*1024 + 'grpc.max_send_message_length': 4*1024*1024, + 'grpc.max_metadata_size': 4*1024*1024 }; client = new testProto.TestService(`localhost:${port}`, creds, options); done(); } }, { - 'grpc.max_receive_message_length': -1 + 'grpc.max_receive_message_length': -1, + 'grpc.max_metadata_size': 4*1024*1024 }); }); after(function() { @@ -168,6 +170,32 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio assert.ifError(error); }); }); + /* The test against the JS server does not work because of + * https://github.com/nodejs/node/issues/35218. The test against the native + * server fails because of an unidentified timeout issue. */ + it.skip('should be able to send very large headers and trailers', function(done) { + done = multiDone(done, 3); + const header = 'X'.repeat(64 * 1024); + const trailer = Buffer.from('Y'.repeat(64 * 1024)); + const metadata = new grpc.Metadata(); + metadata.set('x-grpc-test-echo-initial', header); + metadata.set('x-grpc-test-echo-trailing-bin', trailer); + const call = client.unaryCall({}, metadata, (error, result) => { + assert.ifError(error); + done(); + }); + call.on('metadata', (metadata) => { + assert.deepStrictEqual(metadata.get('x-grpc-test-echo-initial'), + [header]); + done(); + }); + call.on('status', (status) => { + var echo_trailer = status.metadata.get('x-grpc-test-echo-trailing-bin'); + assert(echo_trailer.length === 1); + assert.strictEqual(echo_trailer[0].toString('ascii'), 'Y'.repeat(64 * 1024)); + done(); + }); + }); describe('max message size', function() { // A size that is larger than the default limit const largeMessageSize = 8 * 1024 * 1024; @@ -257,6 +285,9 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio describe('with a server with message size limits and a client without limits', function() { let restrictedServer; let restrictedServerClient; + let restrictedServerClient2; + let restrictedServerClient3; + let restrictedServerClient4; before(function(done) { interopServer.getServer(0, true, (err, serverObj) => { if (err) { @@ -273,6 +304,9 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio 'grpc.max_receive_message_length': -1 }; restrictedServerClient = new testProto.TestService(`localhost:${serverObj.port}`, creds, options); + restrictedServerClient2 = new testProto.TestService(`localhost:${serverObj.port}`, creds, {...options, unique: 1}); + restrictedServerClient3 = new testProto.TestService(`localhost:${serverObj.port}`, creds, {...options, unique: 2}); + restrictedServerClient4 = new testProto.TestService(`localhost:${serverObj.port}`, creds, {...options, unique: 3}); done(); } }, {'grpc.max_send_message_length': 4 * 1024 * 1024}); @@ -284,7 +318,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio restrictedServerClient.unaryCall({payload: {body: largeMessage}}, (error, result) => { assert(error); assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); - const stream = restrictedServerClient.fullDuplexCall(); + const stream = restrictedServerClient2.fullDuplexCall(); stream.write({payload: {body: largeMessage}}); stream.end(); stream.on('data', () => {}); @@ -297,21 +331,19 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); }); it('should get an error when requesting a large message', function(done) { - done = multiDone(done, 2); - restrictedServerClient.unaryCall({response_size: largeMessageSize}, (error, result) => { + restrictedServerClient3.unaryCall({response_size: largeMessageSize}, (error, result) => { assert(error); assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); - done(); - }); - const stream = restrictedServerClient.fullDuplexCall(); - stream.write({response_parameters: [{size: largeMessageSize}]}); - stream.end(); - stream.on('data', () => {}); - stream.on('status', (status) => { - assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED); - done(); - }); - stream.on('error', (error) => { + const stream = restrictedServerClient4.fullDuplexCall(); + stream.write({response_parameters: [{size: largeMessageSize}]}); + stream.end(); + stream.on('data', () => {}); + stream.on('status', (status) => { + assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + stream.on('error', (error) => { + }); }); }); }); diff --git a/test/gulpfile.ts b/test/gulpfile.ts index 05976c17..2024f02c 100644 --- a/test/gulpfile.ts +++ b/test/gulpfile.ts @@ -52,9 +52,9 @@ const testNativeClientJsServer = runTestsWithFixture('js', 'native'); const testJsClientJsServer = runTestsWithFixture('js', 'js'); const test = gulp.series( + testJsClientJsServer, testJsClientNativeServer, - testNativeClientJsServer, - testJsClientJsServer + testNativeClientJsServer ); export { diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 1c2ec8f3..d7df128d 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -22,7 +22,8 @@ var fs = require('fs'); var path = require('path'); var grpc = require('../any_grpc').client; var protoLoader = require('../../packages/proto-loader'); -var GoogleAuth = require('google-auth-library'); + +const { GoogleAuth } = require('google-auth-library'); var protoPackage = protoLoader.loadSync( 'src/proto/grpc/testing/test.proto', @@ -463,60 +464,35 @@ function oauth2Test(client, done, extra) { } function perRpcAuthTest(client, done, extra) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { + var arg = { + fill_username: true, + fill_oauth_scope: true + }; + const creds = grpc.credentials.createFromGoogleCredential(new GoogleAuth({scopes: extra.oauth_scope})); + client.unaryCall(arg, {credentials: creds}, function(err, resp) { assert.ifError(err); - var arg = { - fill_username: true, - fill_oauth_scope: true - }; - var scope = extra.oauth_scope; - if (credential.createScopedRequired() && scope) { - credential = credential.createScoped(scope); + assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL); + assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1); + if (done) { + done(); } - var creds = grpc.credentials.createFromGoogleCredential(credential); - client.unaryCall(arg, {credentials: creds}, function(err, resp) { - assert.ifError(err); - assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL); - assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1); - if (done) { - done(); - } - }); }); } function getApplicationCreds(scope, callback) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { - if (err) { - callback(err); - return; - } - if (credential.createScopedRequired() && scope) { - credential = credential.createScoped(scope); - } - callback(null, grpc.credentials.createFromGoogleCredential(credential)); - }); + callback(null, grpc.credentials.createFromGoogleCredential(new GoogleAuth({scopes: scope}))); } function getOauth2Creds(scope, callback) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { - if (err) { - callback(err); - return; - } - credential = credential.createScoped(scope); - credential.getAccessToken(function(err, token) { - if (err) { - callback(err); - return; - } - var updateMd = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.add('authorization', 'Bearer ' + token); - callback(null, metadata); - }; - callback(null, grpc.credentials.createFromMetadataGenerator(updateMd)); - }); + (new GoogleAuth()).getAccessToken().then((token) => { + var updateMd = function(service_url, callback) { + var metadata = new grpc.Metadata(); + metadata.add('authorization', 'Bearer ' + token); + callback(null, metadata); + }; + callback(null, grpc.credentials.createFromMetadataGenerator(updateMd)); + }, (error) => { + callback(error); }); } diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg new file mode 100644 index 00000000..16a7dc7d --- /dev/null +++ b/test/kokoro/xds-interop.cfg @@ -0,0 +1,24 @@ +# Copyright 2017 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. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" +timeout_mins: 120 +action { + define_artifacts { + regex: "github/grpc/reports/**" + } +} diff --git a/test/package.json b/test/package.json index 2867bc77..4f42f7bf 100644 --- a/test/package.json +++ b/test/package.json @@ -15,7 +15,7 @@ ], "dependencies": { "express": "^4.16.3", - "google-auth-library": "^0.9.2", + "google-auth-library": "^6.1.0", "grpc": "^1.24.2", "lodash": "^4.17.4", "poisson-process": "^1.0.0"