From 9fb6f48bd6900fe345483451e8c9f98856fd2399 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 24 Jul 2020 16:06:37 -0700 Subject: [PATCH 001/123] grpc-js: xDS: add support for dropping calls and reporting drops --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/channel.ts | 6 + .../envoy/api/v2/endpoint/ClusterStats.ts | 117 +++++++ .../v2/endpoint/EndpointLoadMetricStats.ts | 41 +++ .../api/v2/endpoint/UpstreamEndpointStats.ts | 106 +++++++ .../api/v2/endpoint/UpstreamLocalityStats.ts | 108 +++++++ .../load_stats/v2/LoadReportingService.ts | 108 +++++++ .../service/load_stats/v2/LoadStatsRequest.ts | 34 ++ .../load_stats/v2/LoadStatsResponse.ts | 71 +++++ packages/grpc-js/src/generated/lrs.ts | 146 +++++++++ packages/grpc-js/src/load-balancer-eds.ts | 89 +++++- packages/grpc-js/src/picker.ts | 9 + packages/grpc-js/src/xds-client.ts | 290 ++++++++++++++++-- 13 files changed, 1105 insertions(+), 22 deletions(-) create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/endpoint/ClusterStats.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts create mode 100644 packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts create mode 100644 packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts create mode 100644 packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts create mode 100644 packages/grpc-js/src/generated/lrs.ts diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 6473bb32..4c4e59f0 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -48,7 +48,7 @@ "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", + "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/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", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index fe85dec0..f2ad181a 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -390,6 +390,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}` diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/ClusterStats.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/ClusterStats.ts new file mode 100644 index 00000000..8b249289 --- /dev/null +++ b/packages/grpc-js/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/EndpointLoadMetricStats.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts new file mode 100644 index 00000000..a42087c9 --- /dev/null +++ b/packages/grpc-js/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/UpstreamEndpointStats.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts new file mode 100644 index 00000000..4d2df5d2 --- /dev/null +++ b/packages/grpc-js/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/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts new file mode 100644 index 00000000..946ca76b --- /dev/null +++ b/packages/grpc-js/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/service/load_stats/v2/LoadReportingService.ts b/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts new file mode 100644 index 00000000..13d00694 --- /dev/null +++ b/packages/grpc-js/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 '../../../../../index' +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 { + /** + * 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, _envoy_service_load_stats_v2_LoadStatsResponse__Output>): void; + +} diff --git a/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts b/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts new file mode 100644 index 00000000..f2c2393c --- /dev/null +++ b/packages/grpc-js/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/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts b/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts new file mode 100644 index 00000000..9326d869 --- /dev/null +++ b/packages/grpc-js/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/lrs.ts b/packages/grpc-js/src/generated/lrs.ts new file mode 100644 index 00000000..47c5de6d --- /dev/null +++ b/packages/grpc-js/src/generated/lrs.ts @@ -0,0 +1,146 @@ +import * as grpc from '../index'; +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/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 24b464af..15fd7287 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -32,10 +32,10 @@ import { PriorityLoadBalancingConfig, } from './load-balancing-config'; import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; -import { XdsClient, Watcher } from './xds-client'; +import { XdsClient, Watcher, XdsClusterDropStats } from './xds-client'; import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; import { ConnectivityState } from './channel'; -import { UnavailablePicker } from './picker'; +import { UnavailablePicker, Picker, PickResultType } from './picker'; import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; import { LocalitySubchannelAddress } from './load-balancer-priority'; import { Status } from './constants'; @@ -83,8 +83,48 @@ export class EdsLoadBalancer implements LoadBalancer { private nextPriorityChildNumber = 0; + private clusterDropStats: XdsClusterDropStats | null = null; + constructor(private readonly channelControlHelper: ChannelControlHelper) { - this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper); + this.childBalancer = new ChildLoadBalancerHandler({ + createSubchannel: (subchannelAddres, subchannelArgs) => + this.channelControlHelper.createSubchannel( + subchannelAddres, + 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) => { this.latestEdsUpdate = update; @@ -112,6 +152,44 @@ export class EdsLoadBalancer implements LoadBalancer { }; } + /** + * 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. @@ -307,6 +385,11 @@ export class EdsLoadBalancer implements LoadBalancer { this.isWatcherActive = true; } + this.clusterDropStats = this.xdsClient.addClusterDropStats( + lbConfig.eds.cluster, + lbConfig.eds.edsServiceName ?? '' + ); + /* 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. */ 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/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 98bafda3..25bc748b 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -18,6 +18,7 @@ import * as protoLoader from '@grpc/proto-loader'; import { loadPackageDefinition } from './make-client'; import * as adsTypes from './generated/ads'; +import * as lrsTypes from './generated/lrs'; import { createGoogleDefaultCredentials } from './channel-credentials'; import { loadBootstrapInfo } from './xds-bootstrap'; import { ClientDuplexStream, ServiceError } from './call'; @@ -34,6 +35,15 @@ 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'; +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 } 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'; const TRACER_NAME = 'xds_client'; @@ -46,9 +56,13 @@ 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; +let loadedProtos: Promise< + adsTypes.ProtoGrpcType & lrsTypes.ProtoGrpcType +> | null = null; -function loadAdsProtos(): Promise { +function loadAdsProtos(): Promise< + adsTypes.ProtoGrpcType & lrsTypes.ProtoGrpcType +> { if (loadedProtos !== null) { return loadedProtos; } @@ -80,7 +94,7 @@ function loadAdsProtos(): Promise { (packageDefinition) => (loadPackageDefinition( packageDefinition - ) as unknown) as adsTypes.ProtoGrpcType + ) as unknown) as adsTypes.ProtoGrpcType & lrsTypes.ProtoGrpcType ); return loadedProtos; } @@ -91,14 +105,102 @@ export interface Watcher { onResourceDoesNotExist(): void; } +export interface XdsClusterDropStats { + addCallDropped(category: string): 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, + ]; + } + } +} + export class XdsClient { - private node: Node | null = null; - private client: AggregatedDiscoveryServiceClient | null = null; + 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 endpointWatchers: Map< @@ -146,17 +248,32 @@ export class XdsClient { if (this.hasShutdown) { return; } - this.node = { + const node: 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( + this.adsNode = { + ...node, + client_features: ['envoy.lb.does_not_support_overprovisioning'], + }; + this.lrsNode = { + ...node, + client_features: ['envoy.lrs.supports_send_all_clusters'], + }; + this.adsClient = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( bootstrapInfo.xdsServers[0].serverUri, createGoogleDefaultCredentials(), channelArgs ); this.maybeStartAdsStream(); + + this.lrsClient = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( + bootstrapInfo.xdsServers[0].serverUri, + createGoogleDefaultCredentials(), + channelArgs + ); + this.maybeStartLrsStream(); }, (error) => { trace('Failed to initialize xDS Client. ' + error.message); @@ -168,6 +285,8 @@ export class XdsClient { }); } ); + this.statsTimer = setInterval(() => {}, 0); + clearInterval(this.statsTimer); } /** @@ -175,7 +294,7 @@ export class XdsClient { * existing stream, and there */ private maybeStartAdsStream() { - if (this.client === null) { + if (this.adsClient === null) { return; } if (this.adsCall !== null) { @@ -184,7 +303,7 @@ export class XdsClient { if (this.hasShutdown) { return; } - this.adsCall = this.client.StreamAggregatedResources(); + this.adsCall = this.adsClient.StreamAggregatedResources(); this.adsCall.on('data', (message: DiscoveryResponse__Output) => { switch (message.type_url) { case EDS_TYPE_URL: { @@ -276,7 +395,7 @@ export class XdsClient { const endpointWatcherNames = Array.from(this.endpointWatchers.keys()); if (endpointWatcherNames.length > 0) { this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: EDS_TYPE_URL, resource_names: endpointWatcherNames, }); @@ -288,7 +407,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: typeUrl, version_info: versionInfo, response_nonce: nonce, @@ -307,7 +426,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: EDS_TYPE_URL, resource_names: Array.from(this.endpointWatchers.keys()), response_nonce: this.lastEdsNonce, @@ -320,7 +439,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: CDS_TYPE_URL, resource_names: Array.from(this.clusterWatchers.keys()), response_nonce: this.lastCdsNonce, @@ -337,7 +456,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: EDS_TYPE_URL, resource_names: Array.from(this.endpointWatchers.keys()), response_nonce: this.lastEdsNonce, @@ -353,7 +472,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: CDS_TYPE_URL, resource_names: Array.from(this.clusterWatchers.keys()), response_nonce: this.lastCdsNonce, @@ -422,7 +541,7 @@ export class XdsClient { private updateEdsNames() { if (this.adsCall) { this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: EDS_TYPE_URL, resource_names: Array.from(this.endpointWatchers.keys()), response_nonce: this.lastEdsNonce, @@ -434,7 +553,7 @@ export class XdsClient { private updateCdsNames() { if (this.adsCall) { this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: CDS_TYPE_URL, resource_names: Array.from(this.clusterWatchers.keys()), response_nonce: this.lastCdsNonce, @@ -455,6 +574,125 @@ export class XdsClient { // Also do the same for other types of watchers when those are implemented } + private maybeStartLrsStream() { + if (!this.lrsClient) { + return; + } + if (this.lrsCall) { + return; + } + if (this.hasShutdown) { + return; + } + + this.lrsCall = this.lrsClient.streamLoadStats(); + 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; + 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; + clearInterval(this.statsTimer); + /* 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(); + }); + this.lrsCall.write({ + node: this.lrsNode!, + }); + } + + private sendStats() { + if (!this.lrsCall) { + return; + } + 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 @@ -553,9 +791,25 @@ export class XdsClient { } } + addClusterDropStats( + clusterName: string, + edsServiceName: string + ): XdsClusterDropStats { + const clusterStats = this.clusterStatsMap.getOrCreate( + clusterName, + edsServiceName + ); + return { + addCallDropped: (category) => { + const prevCount = clusterStats.callsDropped.get(category) ?? 0; + clusterStats.callsDropped.set(category, prevCount + 1); + }, + }; + } + shutdown(): void { this.adsCall?.cancel(); - this.client?.close(); + this.adsClient?.close(); this.hasShutdown = true; } } From 3c948f5d66abe0a1be00351fdcb922a71e8f9a05 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 27 Jul 2020 09:17:06 -0700 Subject: [PATCH 002/123] Fixes from PR comments --- packages/grpc-js/src/load-balancer-eds.ts | 15 +++++++++------ packages/grpc-js/src/xds-client.ts | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 15fd7287..bc812492 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -87,9 +87,9 @@ export class EdsLoadBalancer implements LoadBalancer { constructor(private readonly channelControlHelper: ChannelControlHelper) { this.childBalancer = new ChildLoadBalancerHandler({ - createSubchannel: (subchannelAddres, subchannelArgs) => + createSubchannel: (subchannelAddress, subchannelArgs) => this.channelControlHelper.createSubchannel( - subchannelAddres, + subchannelAddress, subchannelArgs ), requestReresolution: () => @@ -385,10 +385,13 @@ export class EdsLoadBalancer implements LoadBalancer { this.isWatcherActive = true; } - this.clusterDropStats = this.xdsClient.addClusterDropStats( - lbConfig.eds.cluster, - lbConfig.eds.edsServiceName ?? '' - ); + if (lbConfig.eds.lrsLoadReportingServerName) { + this.clusterDropStats = this.xdsClient.addClusterDropStats( + lbConfig.eds.lrsLoadReportingServerName, + lbConfig.eds.cluster, + lbConfig.eds.edsServiceName ?? '' + ); + } /* If updateAddressList is called after receiving an update and the update * is still valid, we want to update the child config with the information diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 25bc748b..165e545b 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -791,10 +791,24 @@ export class XdsClient { } } + /** + * + * @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 @@ -810,6 +824,8 @@ export class XdsClient { shutdown(): void { this.adsCall?.cancel(); this.adsClient?.close(); + this.lrsCall?.cancel(); + this.lrsClient?.close(); this.hasShutdown = true; } } From 669d25404587806c20483efaa46aa787d495876f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 28 Jul 2020 11:40:42 -0700 Subject: [PATCH 003/123] grpc-js: Add LrsLoadBalancer class --- packages/grpc-js/src/load-balancer-eds.ts | 33 +++- packages/grpc-js/src/load-balancer-lrs.ts | 169 ++++++++++++++++++ packages/grpc-js/src/load-balancer.ts | 2 + packages/grpc-js/src/load-balancing-config.ts | 24 ++- packages/grpc-js/src/xds-client.ts | 81 ++++++++- 5 files changed, 295 insertions(+), 14 deletions(-) create mode 100644 packages/grpc-js/src/load-balancer-lrs.ts diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index bc812492..57aac25b 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -297,16 +297,33 @@ export class EdsLoadBalancer implements LoadBalancer { WeightedTarget >(); for (const localityObj of localityArray) { + /* Use the endpoint picking policy from the config, default to + * round_robin. */ + const endpointPickingPolicy: LoadBalancingConfig[] = [ + ...this.lastestConfig.eds.endpointPickingPolicy, + { name: 'round_robin', round_robin: {} }, + ]; + let childPolicy: LoadBalancingConfig[]; + if (this.lastestConfig.eds.lrsLoadReportingServerName) { + childPolicy = [ + { + name: 'lrs', + lrs: { + cluster_name: this.lastestConfig.eds.cluster, + eds_service_name: this.lastestConfig.eds.edsServiceName ?? '', + lrs_load_reporting_server_name: this.lastestConfig.eds + .lrsLoadReportingServerName, + locality: localityObj.locality, + child_policy: endpointPickingPolicy, + }, + }, + ]; + } else { + childPolicy = endpointPickingPolicy; + } 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: {} }, - ], + child_policy: childPolicy, }); for (const address of localityObj.addresses) { addressList.push({ diff --git a/packages/grpc-js/src/load-balancer-lrs.ts b/packages/grpc-js/src/load-balancer-lrs.ts new file mode 100644 index 00000000..da09593b --- /dev/null +++ b/packages/grpc-js/src/load-balancer-lrs.ts @@ -0,0 +1,169 @@ +/* + * 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, + isLrsLoadBalancingConfig, +} from './load-balancing-config'; +import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +import { ConnectivityState } from './channel'; +import { Picker, PickArgs, PickResultType, PickResult } from './picker'; +import { XdsClusterLocalityStats, XdsClient } from './xds-client'; +import { Filter, BaseFilter, FilterFactory } from './filter'; +import { StatusObject, Call } from './call-stream'; +import { Status } from './constants'; +import { FilterStackFactory } from './filter-stack'; + +const TYPE_NAME = 'lrs'; + +/** + * 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 (!isLrsLoadBalancingConfig(lbConfig)) { + return; + } + if (!(attributes.xdsClient instanceof XdsClient)) { + return; + } + const lrsConfig = lbConfig.lrs; + this.localityStatsReporter = attributes.xdsClient.addClusterLocalityStats( + lrsConfig.lrs_load_reporting_server_name, + lrsConfig.cluster_name, + lrsConfig.eds_service_name, + lrsConfig.locality + ); + const childPolicy: LoadBalancingConfig = getFirstUsableConfig( + lrsConfig.child_policy + ) ?? { name: 'pick_first', pick_first: {} }; + 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); +} diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 227bbe9c..56dd06f3 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -26,6 +26,7 @@ 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'; +import * as load_balancer_lrs from './load-balancer-lrs'; /** * A collection of functions associated with a channel that a load balancer @@ -145,4 +146,5 @@ export function registerAll() { load_balancer_weighted_target.setup(); load_balancer_eds.setup(); load_balancer_cds.setup(); + load_balancer_lrs.setup(); } diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts index 92c4b2b9..d4d7792e 100644 --- a/packages/grpc-js/src/load-balancing-config.ts +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -15,6 +15,8 @@ * */ +import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; + /* 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 @@ -79,6 +81,14 @@ export interface CdsLbConfig { cluster: string; } +export interface LrsLbConfig { + cluster_name: string; + eds_service_name: string; + lrs_load_reporting_server_name: string; + locality: Locality__Output; + child_policy: LoadBalancingConfig[]; +} + export interface PickFirstLoadBalancingConfig { name: 'pick_first'; pick_first: PickFirstConfig; @@ -119,6 +129,11 @@ export interface CdsLoadBalancingConfig { cds: CdsLbConfig; } +export interface LrsLoadBalancingConfig { + name: 'lrs'; + lrs: LrsLbConfig; +} + export type LoadBalancingConfig = | PickFirstLoadBalancingConfig | RoundRobinLoadBalancingConfig @@ -127,7 +142,8 @@ export type LoadBalancingConfig = | PriorityLoadBalancingConfig | WeightedTargetLoadBalancingConfig | EdsLoadBalancingConfig - | CdsLoadBalancingConfig; + | CdsLoadBalancingConfig + | LrsLoadBalancingConfig; export function isRoundRobinLoadBalancingConfig( lbconfig: LoadBalancingConfig @@ -171,6 +187,12 @@ export function isCdsLoadBalancingConfig( return lbconfig.name === 'cds'; } +export function isLrsLoadBalancingConfig( + lbconfig: LoadBalancingConfig +): lbconfig is LrsLoadBalancingConfig { + return lbconfig.name === 'lrs'; +} + /* 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 */ diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 165e545b..5460c52b 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -38,7 +38,10 @@ 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 } from './generated/envoy/api/v2/core/Locality'; +import { + Locality__Output, + Locality, +} from './generated/envoy/api/v2/core/Locality'; import { ClusterStats, _envoy_api_v2_endpoint_ClusterStats_DroppedRequests, @@ -99,6 +102,17 @@ function loadAdsProtos(): Promise< 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; @@ -109,6 +123,11 @@ export interface XdsClusterDropStats { addCallDropped(category: string): void; } +export interface XdsClusterLocalityStats { + addCallStarted(): void; + addCallFinished(fail: boolean): void; +} + interface ClusterLocalityStats { locality: Locality__Output; callsStarted: number; @@ -792,12 +811,12 @@ export class XdsClient { } /** - * + * * @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 + * @param clusterName + * @param edsServiceName */ addClusterDropStats( lrsServer: string, @@ -806,7 +825,7 @@ export class XdsClient { ): XdsClusterDropStats { if (lrsServer !== '') { return { - addCallDropped: category => {} + addCallDropped: (category) => {}, }; } const clusterStats = this.clusterStatsMap.getOrCreate( @@ -821,6 +840,58 @@ export class XdsClient { }; } + 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, + 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.callsSucceeded += 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(); From a3b27be21158daff53dc2a3802969cbf12022903 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 28 Jul 2020 15:43:39 -0700 Subject: [PATCH 004/123] Address a couple of comments --- packages/grpc-js/src/xds-client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 5460c52b..fc2aa17f 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -865,7 +865,7 @@ export class XdsClient { } if (localityStats === null) { localityStats = { - locality, + locality: locality, callsInProgress: 0, callsStarted: 0, callsSucceeded: 0, @@ -878,7 +878,7 @@ export class XdsClient { const finalLocalityStats: ClusterLocalityStats = localityStats; return { addCallStarted: () => { - finalLocalityStats.callsSucceeded += 1; + finalLocalityStats.callsStarted += 1; finalLocalityStats.callsInProgress += 1; }, addCallFinished: (fail) => { From 52eb0df1f8bb7e19d534267893dcb218d0acee38 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 31 Jul 2020 12:00:14 -0700 Subject: [PATCH 005/123] grpc-js: Add XdsResolver and corresponding XdsClient behavior --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/channel.ts | 12 +- .../envoy/api/v2/ScopedRouteConfiguration.ts | 204 ++++ .../v2/HttpConnectionManager.ts | 1039 +++++++++++++++++ .../http_connection_manager/v2/HttpFilter.ts | 34 + .../network/http_connection_manager/v2/Rds.ts | 31 + .../v2/RequestIDExtension.ts | 17 + .../http_connection_manager/v2/ScopedRds.ts | 17 + .../v2/ScopedRouteConfigurationsList.ts | 17 + .../v2/ScopedRoutes.ts | 265 +++++ .../envoy/config/trace/v2/Tracing.ts | 114 ++ .../google/protobuf/MethodOptions.ts | 3 - .../src/generated/http_connection_manager.ts | 228 ++++ packages/grpc-js/src/resolver-dns.ts | 7 +- packages/grpc-js/src/resolver-uds.ts | 7 +- packages/grpc-js/src/resolver-xds.ts | 82 ++ packages/grpc-js/src/resolver.ts | 12 +- .../grpc-js/src/resolving-load-balancer.ts | 136 ++- packages/grpc-js/src/server.ts | 2 +- packages/grpc-js/src/xds-client.ts | 401 +++++-- packages/grpc-js/test/test-resolver.ts | 28 +- 21 files changed, 2487 insertions(+), 171 deletions(-) create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/trace/v2/Tracing.ts create mode 100644 packages/grpc-js/src/generated/http_connection_manager.ts create mode 100644 packages/grpc-js/src/resolver-xds.ts diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4c4e59f0..ee910cfb 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -48,7 +48,7 @@ "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/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", + "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/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", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index f2ad181a..49535c19 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -220,20 +220,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), diff --git a/packages/grpc-js/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts b/packages/grpc-js/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts new file mode 100644 index 00000000..02810bf0 --- /dev/null +++ b/packages/grpc-js/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/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts b/packages/grpc-js/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/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/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts b/packages/grpc-js/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/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/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts b/packages/grpc-js/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/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/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts b/packages/grpc-js/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/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/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts b/packages/grpc-js/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/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/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts b/packages/grpc-js/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/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/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts b/packages/grpc-js/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/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/trace/v2/Tracing.ts b/packages/grpc-js/src/generated/envoy/config/trace/v2/Tracing.ts new file mode 100644 index 00000000..b7ee1c3a --- /dev/null +++ b/packages/grpc-js/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/google/protobuf/MethodOptions.ts b/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts index a5edbd8b..982c7d5d 100644 --- a/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts +++ b/packages/grpc-js/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/http_connection_manager.ts b/packages/grpc-js/src/generated/http_connection_manager.ts new file mode 100644 index 00000000..37fe303b --- /dev/null +++ b/packages/grpc-js/src/generated/http_connection_manager.ts @@ -0,0 +1,228 @@ +import * as grpc from '../index'; +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/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-xds.ts b/packages/grpc-js/src/resolver-xds.ts new file mode 100644 index 00000000..e92fddff --- /dev/null +++ b/packages/grpc-js/src/resolver-xds.ts @@ -0,0 +1,82 @@ +/* + * 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 { Resolver, ResolverListener, registerResolver } from './resolver'; +import { GrpcUri, uriToString } from './uri-parser'; +import { XdsClient } from './xds-client'; +import { ServiceConfig } from './service-config'; +import { StatusObject } from './call-stream'; +import { Status } from './constants'; +import { Metadata } from './metadata'; +import { ChannelOptions } from './channel-options'; + +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; + const xdsClient = new XdsClient( + this.target.path, + { + onValidUpdate: (update: ServiceConfig) => { + 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) { + this.reportResolutionError(); + } + }, + onResourceDoesNotExist: () => { + this.reportResolutionError(); + }, + }, + this.channelOptions + ); + } + } + + static getDefaultAuthority(target: GrpcUri) { + return target.path; + } +} + +export function setup() { + registerResolver('xds', XdsResolver); +} 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..452d3c28 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -20,7 +20,7 @@ import { LoadBalancer, getFirstUsableConfig, } 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'; @@ -35,6 +35,7 @@ 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'; const TRACER_NAME = 'resolving_load_balancer'; @@ -57,6 +58,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 +92,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 +126,72 @@ 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 ?? []; + 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 + ); + }, + 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.ts b/packages/grpc-js/src/server.ts index ebd4504d..683198c5 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -415,7 +415,7 @@ export class Server { }, }; - const resolver = createResolver(portUri, resolverListener); + const resolver = createResolver(portUri, resolverListener, this.options); resolver.updateResolution(); } diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index fc2aa17f..cce79824 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -47,6 +47,9 @@ import { _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'; const TRACER_NAME = 'xds_client'; @@ -58,6 +61,11 @@ 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'; + +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 @@ -73,10 +81,12 @@ function loadAdsProtos(): Promise< .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, @@ -238,6 +248,15 @@ export class XdsClient { private lastCdsNonce = ''; private latestCdsResponses: Cluster__Output[] = []; + private lastLdsVersionInfo = ''; + private lastLdsNonce = ''; + private latestLdsResponse: Listener__Output | null = null; + + private routeConfigName: string | null = null; + private lastRdsVersionInfo = ''; + private lastRdsNonce = ''; + private latestRdsResponse: RouteConfiguration__Output | null = null; + constructor( private targetName: string, private serviceConfigWatcher: Watcher, @@ -308,6 +327,154 @@ export class XdsClient { clearInterval(this.statsTimer); } + private handleAdsResponse(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.nackCds( + `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; + } + case LDS_TYPE_URL: { + let nackError: string | null = null; + for (const resource of message.resources) { + if ( + protoLoader.isAnyExtension(resource) && + resource['@type'] === LDS_TYPE_URL + ) { + const resp = resource as protoLoader.AnyExtension & + Listener__Output; + if (resp.name === this.targetName) { + if (this.validateLdsResponse(resp)) { + this.handleLdsResponse(resp); + this.lastLdsVersionInfo = message.version_info; + this.lastLdsNonce = message.nonce; + this.latestLdsResponse = resp; + } else { + nackError = 'Listener validation failed'; + } + break; + } + } else { + nackError = `Invalid resource type ${ + protoLoader.isAnyExtension(resource) + ? resource['@type'] + : resource.type_url + }`; + break; + } + } + if (nackError) { + this.nackLds(nackError); + } else { + this.ackLds(); + } + break; + } + case RDS_TYPE_URL: { + let nackError: string | null = null; + if (this.routeConfigName === null) { + nackError = 'Unexpected RouteConfiguration response'; + } else { + for (const resource of message.resources) { + if ( + protoLoader.isAnyExtension(resource) && + resource['@type'] === LDS_TYPE_URL + ) { + const resp = resource as protoLoader.AnyExtension & + RouteConfiguration__Output; + if (resp.name === this.routeConfigName) { + if (this.validateRdsResponse(resp)) { + this.handleRdsResponse(resp); + this.lastRdsVersionInfo = message.version_info; + this.lastRdsNonce = message.nonce; + this.latestRdsResponse = resp; + } else { + nackError = 'RouteConfiguration validation failed'; + } + } + } else { + nackError = `Invalid resource type ${ + protoLoader.isAnyExtension(resource) + ? resource['@type'] + : resource.type_url + }`; + break; + } + } + } + if (nackError) { + this.nackRds(nackError); + } else { + this.ackRds(); + } + break; + } + default: + this.nackUnknown(message.type_url, message.version_info, message.nonce); + } + } + /** * Start the ADS stream if the client exists and there is not already an * existing stream, and there @@ -324,81 +491,7 @@ export class XdsClient { } this.adsCall = this.adsClient.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.handleAdsResponse(message); }); this.adsCall.on('error', (error: ServiceError) => { trace( @@ -411,6 +504,30 @@ export class XdsClient { * reconnect */ this.maybeStartAdsStream(); }); + + this.adsCall.write({ + node: this.adsNode!, + type_url: LDS_TYPE_URL, + resource_names: [this.targetName], + }); + + if (this.routeConfigName) { + this.adsCall.write({ + node: this.adsNode!, + type_url: RDS_TYPE_URL, + resource_names: [this.routeConfigName], + }); + } + + const clusterNames = Array.from(this.clusterWatchers.keys()); + if (clusterNames.length > 0) { + this.adsCall.write({ + node: this.adsNode!, + type_url: CDS_TYPE_URL, + resource_names: clusterNames, + }); + } + const endpointWatcherNames = Array.from(this.endpointWatchers.keys()); if (endpointWatcherNames.length > 0) { this.adsCall.write({ @@ -466,6 +583,26 @@ export class XdsClient { }); } + private ackLds() { + this.adsCall?.write({ + node: this.adsNode!, + type_url: LDS_TYPE_URL, + resource_names: [this.targetName], + response_nonce: this.lastLdsNonce, + version_info: this.lastLdsVersionInfo, + }); + } + + private ackRds() { + this.adsCall?.write({ + node: this.adsNode!, + type_url: RDS_TYPE_URL, + resource_names: [this.routeConfigName!], + response_nonce: this.lastRdsNonce, + version_info: this.lastRdsVersionInfo, + }); + } + /** * Reject an EDS update. This should be called without updating the local * nonce and version info. @@ -502,6 +639,32 @@ export class XdsClient { }); } + private nackLds(message: string) { + this.adsCall?.write({ + node: this.adsNode!, + type_url: LDS_TYPE_URL, + resource_names: [this.targetName], + response_nonce: this.lastLdsNonce, + version_info: this.lastLdsVersionInfo, + error_detail: { + message, + }, + }); + } + + private nackRds(message: string) { + this.adsCall?.write({ + node: this.adsNode!, + type_url: RDS_TYPE_URL, + resource_names: this.routeConfigName ? [this.routeConfigName] : [], + response_nonce: this.lastRdsNonce, + version_info: this.lastRdsVersionInfo, + 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 @@ -543,6 +706,36 @@ export class XdsClient { return true; } + private validateLdsResponse(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': + if (!httpConnectionManager.rds?.config_source?.ads) { + return false; + } + break; + case 'route_config': + return this.validateRdsResponse(httpConnectionManager.route_config!); + } + return false; + } + + private validateRdsResponse(message: RouteConfiguration__Output): boolean { + return true; + } + private handleEdsResponse(message: ClusterLoadAssignment__Output) { const watchers = this.endpointWatchers.get(message.cluster_name) ?? []; for (const watcher of watchers) { @@ -557,6 +750,52 @@ export class XdsClient { } } + private handleLdsResponse(message: Listener__Output) { + // 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': + this.routeConfigName = httpConnectionManager.rds!.route_config_name; + this.updateRdsNames(); + break; + case 'route_config': + this.handleRdsResponse(httpConnectionManager.route_config!); + if (this.routeConfigName) { + this.routeConfigName = null; + this.updateRdsNames(); + } + break; + default: + // The validation rules should prevent this + } + } + + private handleRdsResponse(message: RouteConfiguration__Output) { + for (const virtualHost of message.virtual_hosts) { + if (virtualHost.domains.indexOf(this.routeConfigName!) >= 0) { + const route = virtualHost.routes[virtualHost.routes.length - 1]; + if (route.match?.prefix === '' && route.route?.cluster) { + this.serviceConfigWatcher.onValidUpdate({ + methodConfig: [], + loadBalancingConfig: [ + { + name: 'cds', + cds: { + cluster: route.route.cluster, + }, + }, + ], + }); + break; + } + } + } + /* If none of the routes match the one we are looking for, bubble up an + * error. */ + this.serviceConfigWatcher.onResourceDoesNotExist(); + } + private updateEdsNames() { if (this.adsCall) { this.adsCall.write({ @@ -581,16 +820,26 @@ export class XdsClient { } } + private updateRdsNames() { + this.adsCall?.write({ + node: this.adsNode!, + type_url: CDS_TYPE_URL, + resource_names: this.routeConfigName ? [this.routeConfigName] : [], + response_nonce: this.lastRdsNonce, + version_info: this.lastRdsVersionInfo, + }); + } + private reportStreamError(status: StatusObject) { for (const watcherList of [ ...this.endpointWatchers.values(), ...this.clusterWatchers.values(), + [this.serviceConfigWatcher], ]) { for (const watcher of watcherList) { watcher.onTransientError(status); } } - // Also do the same for other types of watchers when those are implemented } private maybeStartLrsStream() { 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(); }); }); From ddec63af2055038ebbe235e73b2371cdd2cfaac0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Aug 2020 11:22:18 -0700 Subject: [PATCH 006/123] grpc-js: Clean up call even if status throws an error --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 11 ++++++++++- packages/grpc-js/src/server-call.ts | 6 ++++++ packages/grpc-js/src/server.ts | 12 +++++++++++- packages/grpc-js/src/subchannel.ts | 2 +- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4c4e59f0..70ebe057 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.1.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 825342a5..45bc665f 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -227,7 +227,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 +610,7 @@ export class Http2CallStream implements Call { } else { code = http2.constants.NGHTTP2_CANCEL; } + this.trace('close http2 stream with code ' + code); this.http2Stream.close(code); } } diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 82d88517..fb76ca03 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -373,6 +373,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'); }); diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index ebd4504d..3580d89a 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -543,11 +543,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); diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index be72680e..736562a6 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -415,7 +415,7 @@ export class Subchannel { ); } trace( - this.subchannelAddress + + this.subchannelAddressString + ' connection closed by GOAWAY with code ' + errorCode ); From d9b3f9f3645c57b2168f92af1994e37f5973d1e5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Aug 2020 11:37:08 -0700 Subject: [PATCH 007/123] grpc-js: Add end(md?: Metadata) method to streaming server calls --- packages/grpc-js/src/server-call.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 82d88517..1e935995 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -91,10 +91,13 @@ export type ServerWritableStream< RequestType, ResponseType > = ServerSurfaceCall & - ObjectWritable & { request: RequestType | null }; + ObjectWritable & { + request: RequestType | null; + end: (metadata?: Metadata) => void; + }; export type ServerDuplexStream = ServerSurfaceCall & ObjectReadable & - ObjectWritable; + ObjectWritable & { end: (metadata?: Metadata) => void }; export class ServerUnaryCallImpl extends EventEmitter implements ServerUnaryCall { @@ -255,6 +258,15 @@ export class ServerDuplexStreamImpl extends Duplex sendMetadata(responseMetadata: Metadata): void { this.call.sendMetadata(responseMetadata); } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + end(metadata?: any) { + if (metadata) { + this.trailingMetadata = metadata; + } + + super.end(); + } } ServerDuplexStreamImpl.prototype._read = From 33a4c85f89591c36cb7001d604ce1f62b65e2db6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Aug 2020 13:03:08 -0700 Subject: [PATCH 008/123] grpc-js: Implement getPeer on the client and server --- packages/grpc-js/src/call-stream.ts | 2 +- packages/grpc-js/src/call.ts | 8 ++++---- packages/grpc-js/src/server-call.ts | 21 +++++++++++++++++---- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 825342a5..2c9f01cb 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -630,7 +630,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/server-call.ts b/packages/grpc-js/src/server-call.ts index 82d88517..bd992773 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -112,7 +112,7 @@ export class ServerUnaryCallImpl extends EventEmitter } getPeer(): string { - throw new Error('not implemented yet'); + return this.call.getPeer(); } sendMetadata(responseMetadata: Metadata): void { @@ -145,7 +145,7 @@ export class ServerReadableStreamImpl } getPeer(): string { - throw new Error('not implemented yet'); + return this.call.getPeer(); } sendMetadata(responseMetadata: Metadata): void { @@ -178,7 +178,7 @@ export class ServerWritableStreamImpl } getPeer(): string { - throw new Error('not implemented yet'); + return this.call.getPeer(); } sendMetadata(responseMetadata: Metadata): void { @@ -249,7 +249,7 @@ export class ServerDuplexStreamImpl extends Duplex } getPeer(): string { - throw new Error('not implemented yet'); + return this.call.getPeer(); } sendMetadata(responseMetadata: Metadata): void { @@ -738,6 +738,19 @@ 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'; + } + } } /* eslint-disable @typescript-eslint/no-explicit-any */ From 0b146c8b076c6b5ca883e536128d00d9b29d0c28 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 5 Aug 2020 12:38:43 -0700 Subject: [PATCH 009/123] Address PR comments --- packages/grpc-js/src/channel.ts | 1 - packages/grpc-js/src/xds-client.ts | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 49535c19..8c369192 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -34,7 +34,6 @@ 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'; diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index cce79824..f867ed7c 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -439,7 +439,7 @@ export class XdsClient { for (const resource of message.resources) { if ( protoLoader.isAnyExtension(resource) && - resource['@type'] === LDS_TYPE_URL + resource['@type'] === RDS_TYPE_URL ) { const resp = resource as protoLoader.AnyExtension & RouteConfiguration__Output; @@ -823,7 +823,7 @@ export class XdsClient { private updateRdsNames() { this.adsCall?.write({ node: this.adsNode!, - type_url: CDS_TYPE_URL, + type_url: RDS_TYPE_URL, resource_names: this.routeConfigName ? [this.routeConfigName] : [], response_nonce: this.lastRdsNonce, version_info: this.lastRdsVersionInfo, From 76bb17091bbcd4afe70a240d51aa506b3543f56b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 5 Aug 2020 12:57:54 -0700 Subject: [PATCH 010/123] Stop processing RDS requests after finding the matching one --- packages/grpc-js/src/xds-client.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index f867ed7c..f5725d78 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -452,6 +452,7 @@ export class XdsClient { } else { nackError = 'RouteConfiguration validation failed'; } + break; } } else { nackError = `Invalid resource type ${ From 5dcce9ebf17181a32afa6fe994174ca9343b9a6e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 6 Aug 2020 13:08:59 -0700 Subject: [PATCH 011/123] grpc-js: XdsClient: separate ADS stream handling by message type --- packages/grpc-js/src/xds-client.ts | 1096 ++++++++++++++-------------- 1 file changed, 539 insertions(+), 557 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index f5725d78..4375c77a 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -33,7 +33,10 @@ 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 { + 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'; @@ -50,6 +53,7 @@ import { UpstreamLocalityStats } from './generated/envoy/api/v2/endpoint/Upstrea 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'; const TRACER_NAME = 'xds_client'; @@ -64,6 +68,13 @@ 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'; @@ -211,6 +222,424 @@ class ClusterLoadReportMap { } } +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); + } + 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(() => { + watcher.onValidUpdate(message); + }); + } + } + if (addedServiceName) { + this.updateResourceNames(); + } + } + + removeWatcher( + edsServiceName: string, + watcher: Watcher + ): void { + const watchersEntry = this.watchers.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.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; + } + + handleResponses(responses: ClusterLoadAssignment__Output[]) { + for (const message of responses) { + if (!this.validateResponse(message)) { + return 'ClusterLoadAssignment validation failed'; + } + } + this.latestResponses = responses; + for (const message of responses) { + const watchers = this.watchers.get(message.cluster_name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); + } + } + 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 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 { + 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(() => { + watcher.onValidUpdate(message); + }); + } + } + if (addedServiceName) { + this.updateResourceNames(); + } + } + + removeWatcher(clusterName: string, watcher: Watcher): void { + 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; + } + + handleResponses(responses: Cluster__Output[]): string | null { + for (const message of responses) { + if (!this.validateResponse(message)) { + return 'Cluster validation failed'; + } + } + this.latestResponses = responses; + for (const message of responses) { + const watchers = this.watchers.get(message.name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); + } + } + 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 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.routeConfigName!) >= 0) { + const route = virtualHost.routes[virtualHost.routes.length - 1]; + if (route.match?.prefix === '' && route.route?.cluster) { + this.watcher.onValidUpdate({ + methodConfig: [], + loadBalancingConfig: [ + { + name: 'cds', + cds: { + cluster: route.route.cluster, + }, + }, + ], + }); + break; + } + } + } + /* 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 { + 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 { + 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': + this.rdsState.setRouteConfigName( + httpConnectionManager.rds!.route_config_name + ); + break; + case 'route_config': + this.rdsState.setRouteConfigName(null); + this.rdsState.handleSingleMessage( + httpConnectionManager.route_config! + ); + break; + default: + // The validation rules should prevent this + } + } else { + return 'Listener validation failed'; + } + } + } + throw new Error('Method not implemented.'); + } + + 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( + `Invalid resource type ${ + protoLoader.isAnyExtension(resource) + ? resource['@type'] + : resource.type_url + }` + ); + } + } + return result; +} + export class XdsClient { private adsNode: Node | null = null; private adsClient: AggregatedDiscoveryServiceClient | null = null; @@ -232,36 +661,30 @@ export class XdsClient { 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[] = []; - - private lastLdsVersionInfo = ''; - private lastLdsNonce = ''; - private latestLdsResponse: Listener__Output | null = null; - - private routeConfigName: string | null = null; - private lastRdsVersionInfo = ''; - private lastRdsNonce = ''; - private latestRdsResponse: RouteConfiguration__Output | null = null; + private adsState: AdsState; constructor( - private targetName: string, - private serviceConfigWatcher: Watcher, + targetName: string, + serviceConfigWatcher: Watcher, channelOptions: ChannelOptions ) { + const edsState = new EdsState(() => { + this.updateNames(EDS_TYPE_URL); + }); + const cdsState = new CdsState(() => { + this.updateNames(CDS_TYPE_URL); + }); + const rdsState = new RdsState(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 @@ -328,151 +751,44 @@ export class XdsClient { } 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: { - 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(); + case EDS_TYPE_URL: + errorString = this.adsState[message.type_url].handleResponses( + getResponseMessages(message.type_url, message.resources) + ); 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.nackCds( - `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(); + case CDS_TYPE_URL: + errorString = this.adsState[message.type_url].handleResponses( + getResponseMessages(message.type_url, message.resources) + ); break; - } - case LDS_TYPE_URL: { - let nackError: string | null = null; - for (const resource of message.resources) { - if ( - protoLoader.isAnyExtension(resource) && - resource['@type'] === LDS_TYPE_URL - ) { - const resp = resource as protoLoader.AnyExtension & - Listener__Output; - if (resp.name === this.targetName) { - if (this.validateLdsResponse(resp)) { - this.handleLdsResponse(resp); - this.lastLdsVersionInfo = message.version_info; - this.lastLdsNonce = message.nonce; - this.latestLdsResponse = resp; - } else { - nackError = 'Listener validation failed'; - } - break; - } - } else { - nackError = `Invalid resource type ${ - protoLoader.isAnyExtension(resource) - ? resource['@type'] - : resource.type_url - }`; - break; - } - } - if (nackError) { - this.nackLds(nackError); - } else { - this.ackLds(); - } + case RDS_TYPE_URL: + errorString = this.adsState[message.type_url].handleResponses( + getResponseMessages(message.type_url, message.resources) + ); break; - } - case RDS_TYPE_URL: { - let nackError: string | null = null; - if (this.routeConfigName === null) { - nackError = 'Unexpected RouteConfiguration response'; - } else { - for (const resource of message.resources) { - if ( - protoLoader.isAnyExtension(resource) && - resource['@type'] === RDS_TYPE_URL - ) { - const resp = resource as protoLoader.AnyExtension & - RouteConfiguration__Output; - if (resp.name === this.routeConfigName) { - if (this.validateRdsResponse(resp)) { - this.handleRdsResponse(resp); - this.lastRdsVersionInfo = message.version_info; - this.lastRdsNonce = message.nonce; - this.latestRdsResponse = resp; - } else { - nackError = 'RouteConfiguration validation failed'; - } - break; - } - } else { - nackError = `Invalid resource type ${ - protoLoader.isAnyExtension(resource) - ? resource['@type'] - : resource.type_url - }`; - break; - } - } - } - if (nackError) { - this.nackRds(nackError); - } else { - this.ackRds(); - } + case LDS_TYPE_URL: + errorString = this.adsState[message.type_url].handleResponses( + getResponseMessages(message.type_url, message.resources) + ); break; - } default: - this.nackUnknown(message.type_url, message.version_info, message.nonce); + errorString = `Unknown type_url ${message.type_url}`; + } + if (errorString === null) { + /* 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 { + this.nack(message.type_url, errorString); } } @@ -506,341 +822,79 @@ export class XdsClient { this.maybeStartAdsStream(); }); - this.adsCall.write({ - node: this.adsNode!, - type_url: LDS_TYPE_URL, - resource_names: [this.targetName], - }); - - if (this.routeConfigName) { - this.adsCall.write({ - node: this.adsNode!, - type_url: RDS_TYPE_URL, - resource_names: [this.routeConfigName], - }); + 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]; + state.nonce = ''; + state.versionInfo = ''; + if (state.getResourceNames().length > 0) { + this.updateNames(typeUrl); + } } - - const clusterNames = Array.from(this.clusterWatchers.keys()); - if (clusterNames.length > 0) { - this.adsCall.write({ - node: this.adsNode!, - type_url: CDS_TYPE_URL, - resource_names: clusterNames, - }); - } - - const endpointWatcherNames = Array.from(this.endpointWatchers.keys()); - if (endpointWatcherNames.length > 0) { - this.adsCall.write({ - node: this.adsNode!, - 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.adsNode!, - 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 + * Acknowledge an 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.adsNode!, - 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.adsNode!, - type_url: CDS_TYPE_URL, - resource_names: Array.from(this.clusterWatchers.keys()), - response_nonce: this.lastCdsNonce, - version_info: this.lastCdsVersionInfo, - }); - } - - private ackLds() { - this.adsCall?.write({ - node: this.adsNode!, - type_url: LDS_TYPE_URL, - resource_names: [this.targetName], - response_nonce: this.lastLdsNonce, - version_info: this.lastLdsVersionInfo, - }); - } - - private ackRds() { - this.adsCall?.write({ - node: this.adsNode!, - type_url: RDS_TYPE_URL, - resource_names: [this.routeConfigName!], - response_nonce: this.lastRdsNonce, - version_info: this.lastRdsVersionInfo, - }); + ack(typeUrl: AdsTypeUrl) { + this.updateNames(typeUrl); } /** - * Reject an EDS update. This should be called without updating the local + * Reject an 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.adsNode!, - 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.adsNode!, - type_url: CDS_TYPE_URL, - resource_names: Array.from(this.clusterWatchers.keys()), - response_nonce: this.lastCdsNonce, - version_info: this.lastCdsVersionInfo, - error_detail: { - message, - }, - }); - } - - private nackLds(message: string) { - this.adsCall?.write({ - node: this.adsNode!, - type_url: LDS_TYPE_URL, - resource_names: [this.targetName], - response_nonce: this.lastLdsNonce, - version_info: this.lastLdsVersionInfo, - error_detail: { - message, - }, - }); - } - - private nackRds(message: string) { - this.adsCall?.write({ - node: this.adsNode!, - type_url: RDS_TYPE_URL, - resource_names: this.routeConfigName ? [this.routeConfigName] : [], - response_nonce: this.lastRdsNonce, - version_info: this.lastRdsVersionInfo, - 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 validateLdsResponse(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': - if (!httpConnectionManager.rds?.config_source?.ads) { - return false; - } - break; - case 'route_config': - return this.validateRdsResponse(httpConnectionManager.route_config!); - } - return false; - } - - private validateRdsResponse(message: RouteConfiguration__Output): boolean { - 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 handleLdsResponse(message: Listener__Output) { - // 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': - this.routeConfigName = httpConnectionManager.rds!.route_config_name; - this.updateRdsNames(); - break; - case 'route_config': - this.handleRdsResponse(httpConnectionManager.route_config!); - if (this.routeConfigName) { - this.routeConfigName = null; - this.updateRdsNames(); - } + 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: - // The validation rules should prevent this + resourceNames = []; + nonce = ''; + versionInfo = ''; } - } - - private handleRdsResponse(message: RouteConfiguration__Output) { - for (const virtualHost of message.virtual_hosts) { - if (virtualHost.domains.indexOf(this.routeConfigName!) >= 0) { - const route = virtualHost.routes[virtualHost.routes.length - 1]; - if (route.match?.prefix === '' && route.route?.cluster) { - this.serviceConfigWatcher.onValidUpdate({ - methodConfig: [], - loadBalancingConfig: [ - { - name: 'cds', - cds: { - cluster: route.route.cluster, - }, - }, - ], - }); - break; - } - } - } - /* If none of the routes match the one we are looking for, bubble up an - * error. */ - this.serviceConfigWatcher.onResourceDoesNotExist(); - } - - private updateEdsNames() { - if (this.adsCall) { - this.adsCall.write({ - node: this.adsNode!, - 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.adsNode!, - type_url: CDS_TYPE_URL, - resource_names: Array.from(this.clusterWatchers.keys()), - response_nonce: this.lastCdsNonce, - version_info: this.lastCdsVersionInfo, - }); - } - } - - private updateRdsNames() { this.adsCall?.write({ node: this.adsNode!, - type_url: RDS_TYPE_URL, - resource_names: this.routeConfigName ? [this.routeConfigName] : [], - response_nonce: this.lastRdsNonce, - version_info: this.lastRdsVersionInfo, + type_url: typeUrl, + resource_names: resourceNames, + response_nonce: nonce, + version_info: versionInfo, + error_detail: { + message: message, + }, + }); + } + + private updateNames(typeUrl: AdsTypeUrl) { + 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) { - for (const watcherList of [ - ...this.endpointWatchers.values(), - ...this.clusterWatchers.values(), - [this.serviceConfigWatcher], - ]) { - for (const watcher of watcherList) { - watcher.onTransientError(status); - } - } + 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() { @@ -967,29 +1021,7 @@ export class XdsClient { 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); - }); - } - } + this.adsState[EDS_TYPE_URL].addWatcher(edsServiceName, watcher); } removeEndpointWatcher( @@ -997,67 +1029,17 @@ export class XdsClient { 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(); - } + this.adsState[EDS_TYPE_URL].removeWatcher(edsServiceName, watcher); } 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); - }); - } - } + this.adsState[CDS_TYPE_URL].addWatcher(clusterName, watcher); } 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(); - } + this.adsState[CDS_TYPE_URL].removeWatcher(clusterName, watcher); } /** From 6c0012499ab7b6b252fdb2e46728c29cac923f0e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 6 Aug 2020 13:30:24 -0700 Subject: [PATCH 012/123] Implement onResourceDoesNotExist notifications --- packages/grpc-js/src/xds-client.ts | 51 ++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 4375c77a..d29d29b8 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -332,6 +332,22 @@ class EdsState implements XdsStreamState { 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)) { + for (const watcher of watcherList) { + watcher.onResourceDoesNotExist(); + } + } + } + } + handleResponses(responses: ClusterLoadAssignment__Output[]) { for (const message of responses) { if (!this.validateResponse(message)) { @@ -339,12 +355,15 @@ class EdsState implements XdsStreamState { } } 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); } } + this.handleMissingNames(allClusterNames); return null; } @@ -368,7 +387,10 @@ class CdsState implements XdsStreamState { private latestResponses: Cluster__Output[] = []; - constructor(private updateResourceNames: () => void) {} + constructor( + private edsState: EdsState, + private updateResourceNames: () => void + ) {} /** * Add the watcher to the watcher list. Returns true if the list of resource @@ -442,6 +464,22 @@ class CdsState implements XdsStreamState { 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 + */ + private handleMissingNames(allClusterNames: Set) { + for (const [edsServiceName, watcherList] of this.watchers.entries()) { + if (!allClusterNames.has(edsServiceName)) { + for (const watcher of watcherList) { + watcher.onResourceDoesNotExist(); + } + } + } + } + handleResponses(responses: Cluster__Output[]): string | null { for (const message of responses) { if (!this.validateResponse(message)) { @@ -449,12 +487,21 @@ class CdsState implements XdsStreamState { } } 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); } } + this.handleMissingNames(allClusterNames); + this.edsState.handleMissingNames(allEdsServiceNames); return null; } @@ -671,7 +718,7 @@ export class XdsClient { const edsState = new EdsState(() => { this.updateNames(EDS_TYPE_URL); }); - const cdsState = new CdsState(() => { + const cdsState = new CdsState(edsState, () => { this.updateNames(CDS_TYPE_URL); }); const rdsState = new RdsState(serviceConfigWatcher, () => { From cb63d6afcd1f5b88d565018cdbcfeff9a672f49f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 10 Aug 2020 15:27:26 -0700 Subject: [PATCH 013/123] grpc-js: Add xDS interop client and associated generated code --- .../generated/grpc/testing/BoolValue.ts | 26 +++ .../generated/grpc/testing/EchoStatus.ts | 20 ++ .../interop/generated/grpc/testing/Empty.ts | 26 +++ .../generated/grpc/testing/GrpclbRouteType.ts | 24 ++ .../grpc/testing/LoadBalancerStatsRequest.ts | 24 ++ .../grpc/testing/LoadBalancerStatsResponse.ts | 40 ++++ .../grpc/testing/LoadBalancerStatsService.ts | 37 +++ .../interop/generated/grpc/testing/Payload.ts | 31 +++ .../generated/grpc/testing/PayloadType.ts | 11 + .../generated/grpc/testing/ReconnectInfo.ts | 22 ++ .../generated/grpc/testing/ReconnectParams.ts | 18 ++ .../grpc/testing/ReconnectService.ts | 40 ++++ .../grpc/testing/ResponseParameters.ts | 47 ++++ .../generated/grpc/testing/SimpleRequest.ts | 106 +++++++++ .../generated/grpc/testing/SimpleResponse.ts | 68 ++++++ .../grpc/testing/StreamingInputCallRequest.ts | 38 +++ .../testing/StreamingInputCallResponse.ts | 22 ++ .../testing/StreamingOutputCallRequest.ts | 56 +++++ .../testing/StreamingOutputCallResponse.ts | 23 ++ .../generated/grpc/testing/TestService.ts | 202 ++++++++++++++++ .../grpc/testing/UnimplementedService.ts | 38 +++ .../grpc/testing/XdsUpdateHealthService.ts | 38 +++ packages/grpc-js/interop/generated/test.ts | 60 +++++ .../grpc-js/interop/xds-interop-client.ts | 220 ++++++++++++++++++ 24 files changed, 1237 insertions(+) create mode 100644 packages/grpc-js/interop/generated/grpc/testing/BoolValue.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/EchoStatus.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/Empty.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/GrpclbRouteType.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/Payload.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/PayloadType.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/ReconnectInfo.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/ReconnectParams.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/ResponseParameters.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/SimpleRequest.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/SimpleResponse.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallRequest.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallResponse.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallRequest.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallResponse.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/TestService.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts create mode 100644 packages/grpc-js/interop/generated/test.ts create mode 100644 packages/grpc-js/interop/xds-interop-client.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/BoolValue.ts b/packages/grpc-js/interop/generated/grpc/testing/BoolValue.ts new file mode 100644 index 00000000..a1e31ab3 --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/EchoStatus.ts b/packages/grpc-js/interop/generated/grpc/testing/EchoStatus.ts new file mode 100644 index 00000000..d5da7501 --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/Empty.ts b/packages/grpc-js/interop/generated/grpc/testing/Empty.ts new file mode 100644 index 00000000..d79db52b --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/GrpclbRouteType.ts b/packages/grpc-js/interop/generated/grpc/testing/GrpclbRouteType.ts new file mode 100644 index 00000000..8ab0146b --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts b/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts new file mode 100644 index 00000000..189d871b --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts b/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts new file mode 100644 index 00000000..184a6e25 --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/LoadBalancerStatsService.ts b/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts new file mode 100644 index 00000000..eece848b --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts @@ -0,0 +1,37 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '../../../../src' +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/interop/generated/grpc/testing/Payload.ts b/packages/grpc-js/interop/generated/grpc/testing/Payload.ts new file mode 100644 index 00000000..87fc0cf3 --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/PayloadType.ts b/packages/grpc-js/interop/generated/grpc/testing/PayloadType.ts new file mode 100644 index 00000000..3cf9d375 --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/ReconnectInfo.ts b/packages/grpc-js/interop/generated/grpc/testing/ReconnectInfo.ts new file mode 100644 index 00000000..616de9eb --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/ReconnectParams.ts b/packages/grpc-js/interop/generated/grpc/testing/ReconnectParams.ts new file mode 100644 index 00000000..1337b568 --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/ReconnectService.ts b/packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts new file mode 100644 index 00000000..3829506b --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts @@ -0,0 +1,40 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '../../../../src' +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/interop/generated/grpc/testing/ResponseParameters.ts b/packages/grpc-js/interop/generated/grpc/testing/ResponseParameters.ts new file mode 100644 index 00000000..9bd24ee3 --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/SimpleRequest.ts b/packages/grpc-js/interop/generated/grpc/testing/SimpleRequest.ts new file mode 100644 index 00000000..b03f6f6d --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/SimpleResponse.ts b/packages/grpc-js/interop/generated/grpc/testing/SimpleResponse.ts new file mode 100644 index 00000000..7a96e7df --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/StreamingInputCallRequest.ts b/packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallRequest.ts new file mode 100644 index 00000000..db9d8d40 --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/StreamingInputCallResponse.ts b/packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallResponse.ts new file mode 100644 index 00000000..1703e755 --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/StreamingOutputCallRequest.ts b/packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallRequest.ts new file mode 100644 index 00000000..0d7bff2f --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/StreamingOutputCallResponse.ts b/packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallResponse.ts new file mode 100644 index 00000000..9b8f49e3 --- /dev/null +++ b/packages/grpc-js/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/interop/generated/grpc/testing/TestService.ts b/packages/grpc-js/interop/generated/grpc/testing/TestService.ts new file mode 100644 index 00000000..b95b7a97 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/TestService.ts @@ -0,0 +1,202 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '../../../../src' +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/interop/generated/grpc/testing/UnimplementedService.ts b/packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts new file mode 100644 index 00000000..afbf9117 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts @@ -0,0 +1,38 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '../../../../src' +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/interop/generated/grpc/testing/XdsUpdateHealthService.ts b/packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts new file mode 100644 index 00000000..f27a461e --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts @@ -0,0 +1,38 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '../../../../src' +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/interop/generated/test.ts b/packages/grpc-js/interop/generated/test.ts new file mode 100644 index 00000000..a5c95d95 --- /dev/null +++ b/packages/grpc-js/interop/generated/test.ts @@ -0,0 +1,60 @@ +import * as grpc from '../../src'; +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/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts new file mode 100644 index 00000000..e056fb08 --- /dev/null +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -0,0 +1,220 @@ +/* + * 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 '../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'; + +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; + +interface CallEndNotifier { + onCallSucceeded(peerName: string): void; + onCallFailed(): void; +} + +class CallSubscriber { + private callsStarted = 0; + private callsSucceededByPeer: {[key: string]: number} = {}; + private callsSucceeded = 0; + private callsFinished = 0; + + constructor(private callGoal: number, private onFinished: () => void) {} + + addCallStarted(): void { + this.callsStarted += 1; + } + + private maybeOnFinished() { + if (this.callsFinished == this.callGoal) { + this.onFinished(); + } + } + + addCallSucceeded(peerName: string): void { + if (peerName in this.callsSucceededByPeer) { + this.callsSucceededByPeer[peerName] += 1; + } else { + this.callsSucceededByPeer[peerName] = 1; + } + this.callsSucceeded += 1; + this.callsFinished += 1; + this.maybeOnFinished(); + } + addCallFailed(): void { + this.callsFinished += 1; + this.maybeOnFinished(); + } + + needsMoreCalls(): boolean { + return this.callsStarted < this.callGoal; + } + + getFinalStats(): LoadBalancerStatsResponse { + 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: () => { + for (const subscriber of callSubscribers) { + subscriber.addCallFailed(); + } + } + } + } +} + +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 call = client.emptyCall({}, (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(); + } else { + anyCallSucceeded = true; + if (gotMetadata) { + if (hostname === null) { + notifier.onCallFailed() + } 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(); + } else { + notifier.onCallSucceeded(hostname); + } + } + }) + }, 1000/qps); +} + + + +function main() { + const argv = yargs + .string(['fail_on_failed_rpcs', 'server', 'stats_port']) + .number(['num_channels', 'qps']) + .require(['fail_on_failed_rpcs', 'num_channels', 'qps', 'server', 'stats_port']) + .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. */ + 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) => { + callStatsTracker.getCallStats(call.request.num_rpcs, call.request.timeout_sec).then((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; + } + server.start(); + }); +} + +if (require.main === module) { + main(); +} \ No newline at end of file From 409ad9502024519788ca1a32085cac64d6c1b536 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 10 Aug 2020 15:48:42 -0700 Subject: [PATCH 014/123] Add dependencies for xDS, plus some fixes --- packages/grpc-js/package.json | 9 ++++++--- .../src/load-balancer-weighted-target.ts | 2 +- packages/grpc-js/src/server-call.ts | 18 ++++++++---------- packages/grpc-js/src/server.ts | 19 ++++++++++--------- packages/grpc-js/tsconfig.json | 3 ++- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index ee910cfb..b4c2d285 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,7 +15,6 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "^0.6.0-pre6", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", @@ -24,9 +23,9 @@ "@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": [ { @@ -49,6 +49,7 @@ "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/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 ../../src grpc/testing/test.proto", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", @@ -58,6 +59,8 @@ "posttest": "npm run check" }, "dependencies": { + "@grpc/proto-loader": "^0.6.0-pre14", + "google-auth-library": "^5.10.1", "semver": "^6.2.0" }, "files": [ diff --git a/packages/grpc-js/src/load-balancer-weighted-target.ts b/packages/grpc-js/src/load-balancer-weighted-target.ts index 04145914..e8a5fe65 100644 --- a/packages/grpc-js/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js/src/load-balancer-weighted-target.ts @@ -229,7 +229,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: diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 82d88517..2a75f01e 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -81,7 +81,7 @@ export type ServerSurfaceCall = { } & EventEmitter; export type ServerUnaryCall = ServerSurfaceCall & { - request: RequestType | null; + request: RequestType; }; export type ServerReadableStream< RequestType, @@ -91,7 +91,7 @@ export type ServerWritableStream< RequestType, ResponseType > = ServerSurfaceCall & - ObjectWritable & { request: RequestType | null }; + ObjectWritable & { request: RequestType }; export type ServerDuplexStream = ServerSurfaceCall & ObjectReadable & ObjectWritable; @@ -99,15 +99,14 @@ export type ServerDuplexStream = ServerSurfaceCall & 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); } @@ -157,17 +156,16 @@ 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); @@ -268,7 +266,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; @@ -506,7 +504,7 @@ export class Http2ServerCallStream< async sendUnaryMessage( err: ServerErrorResponse | ServerStatusResponse | null, - value: ResponseType | null, + value?: ResponseType | null, metadata?: Metadata, flags?: number ) { diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 683198c5..8fdacd4d 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -622,22 +622,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; } + + const emitter = new ServerUnaryCallImpl( + call, + metadata, + request + ); - emitter.request = request; handler.func( emitter, ( err: ServerErrorResponse | ServerStatusResponse | null, - value: ResponseType | null, + value?: ResponseType | null, trailer?: Metadata, flags?: number ) => { @@ -659,7 +660,7 @@ function handleClientStreaming( function respond( err: ServerErrorResponse | ServerStatusResponse | null, - value: ResponseType | null, + value?: ResponseType | null, trailer?: Metadata, flags?: number ) { @@ -689,10 +690,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/tsconfig.json b/packages/grpc-js/tsconfig.json index ba675db7..65ebf089 100644 --- a/packages/grpc-js/tsconfig.json +++ b/packages/grpc-js/tsconfig.json @@ -10,6 +10,7 @@ }, "include": [ "src/**/*.ts", - "test/**/*.ts" + "test/**/*.ts", + "interop/**/*.ts" ] } From 94a4779bb68462c0175e02939ebb3513c8ba3d65 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 10 Aug 2020 15:49:24 -0700 Subject: [PATCH 015/123] Add xDS interop proto files --- .../grpc-js/proto/grpc/testing/empty.proto | 28 +++ .../grpc-js/proto/grpc/testing/messages.proto | 214 ++++++++++++++++++ .../grpc-js/proto/grpc/testing/test.proto | 92 ++++++++ 3 files changed, 334 insertions(+) create mode 100644 packages/grpc-js/proto/grpc/testing/empty.proto create mode 100644 packages/grpc-js/proto/grpc/testing/messages.proto create mode 100644 packages/grpc-js/proto/grpc/testing/test.proto diff --git a/packages/grpc-js/proto/grpc/testing/empty.proto b/packages/grpc-js/proto/grpc/testing/empty.proto new file mode 100644 index 00000000..6a0aa88d --- /dev/null +++ b/packages/grpc-js/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/proto/grpc/testing/messages.proto b/packages/grpc-js/proto/grpc/testing/messages.proto new file mode 100644 index 00000000..70e34277 --- /dev/null +++ b/packages/grpc-js/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/proto/grpc/testing/test.proto b/packages/grpc-js/proto/grpc/testing/test.proto new file mode 100644 index 00000000..9d0fadd9 --- /dev/null +++ b/packages/grpc-js/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); +} From ba7a035770e5ca9865390ef1ae220142b9019ecd Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 10 Aug 2020 15:50:46 -0700 Subject: [PATCH 016/123] Enable 'xds' target scheme --- packages/grpc-js/src/resolver.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 57c750ae..0c4c0d6b 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -18,6 +18,7 @@ import { ServiceConfig } from './service-config'; import * as resolver_dns from './resolver-dns'; import * as resolver_uds from './resolver-uds'; +import * as resolver_xds from './resolver-xds'; import { StatusObject } from './call-stream'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; @@ -156,4 +157,5 @@ export function mapUriDefaultScheme(target: GrpcUri): GrpcUri | null { export function registerAll() { resolver_dns.setup(); resolver_uds.setup(); + resolver_xds.setup(); } From f0ed1aba14ff53e356343178d5634af5e624a3f6 Mon Sep 17 00:00:00 2001 From: Martin <1224973+mavaa@users.noreply.github.com> Date: Wed, 12 Aug 2020 16:51:42 +0200 Subject: [PATCH 017/123] Fix incorrectly named grpc-tools flag Was "--generate_package_definitions" (with an s) but should be "generate_package_definition" as in the documentation here: https://github.com/grpc/grpc-node/tree/master/packages/grpc-tools --- packages/grpc-js/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index 4d0cb548..dadcd188 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -28,7 +28,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 From 1583786478042de1dd61300e810bc87d442d6c88 Mon Sep 17 00:00:00 2001 From: Thomas Hunter II Date: Sun, 16 Aug 2020 13:50:23 -0700 Subject: [PATCH 018/123] Add link to grpc docs in @grpc/grpc-js README - Adds a link to `grpc` documentation - Addresses some of the concerns in #1540 --- packages/grpc-js/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index dadcd188..e34cee9c 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 From 74930526724826892bb7696412bd6e7c2c2b4ced Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 18 Aug 2020 15:13:12 -0700 Subject: [PATCH 019/123] grpc-js: Move @types/node to a production dependency --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index ee910cfb..839c67f3 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -21,7 +21,6 @@ "@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", "clang-format": "^1.0.55", @@ -58,6 +57,7 @@ "posttest": "npm run check" }, "dependencies": { + "@types/node": "^12.12.47", "semver": "^6.2.0" }, "files": [ From 917b4fca77fc9ee81c8dc71d38043f54c4d98562 Mon Sep 17 00:00:00 2001 From: Richard Pringle Date: Wed, 19 Aug 2020 10:24:20 -0400 Subject: [PATCH 020/123] Prevent mutation of default headers --- packages/grpc-js/src/server-call.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 82d88517..bdefa68a 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -413,7 +413,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); } From 5abb47390fa34078f5afd21da23bf488d79c0840 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 09:24:57 -0700 Subject: [PATCH 021/123] grpc-js: Move a couple of dev dependencies to prod --- packages/grpc-js/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index f207c753..7deb248e 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.4", + "version": "1.1.5", "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,7 +15,6 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "^0.6.0-pre6", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", @@ -25,7 +24,6 @@ "@types/semver": "^6.0.1", "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", @@ -57,7 +55,9 @@ "posttest": "npm run check" }, "dependencies": { + "@grpc/proto-loader": "^0.6.0-pre14", "@types/node": "^12.12.47", + "google-auth-library": "^6.0.0", "semver": "^6.2.0" }, "files": [ From 305e192700546f355b32263c74a9ee8c4601b1d2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 13:31:23 -0700 Subject: [PATCH 022/123] Add xds interop test script to Linux tests --- packages/grpc-js/src/xds-client.ts | 2 -- run-tests.sh | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index d29d29b8..64f6a581 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -877,8 +877,6 @@ export class XdsClient { ]; for (const typeUrl of allTypeUrls) { const state = this.adsState[typeUrl]; - state.nonce = ''; - state.versionInfo = ''; if (state.getResourceNames().length > 0) { this.updateNames(typeUrl); } diff --git a/run-tests.sh b/run-tests.sh index f23475b9..ca4501d0 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -75,6 +75,12 @@ do npm test || FAILED="true" done +if [ "$OS" = "Linux" ] +then + # Run the xds interop tests only on Linux + ./packages/grpc-js/scripts/xds.sh +fi + set +ex nvm use 8 set -ex From 9a73734650f854037050c379579dfea5f6bf2a1d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 13:36:16 -0700 Subject: [PATCH 023/123] Actually add the xds interop script --- packages/grpc-js/scripts/xds.sh | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 packages/grpc-js/scripts/xds.sh diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh new file mode 100644 index 00000000..1b6fde5d --- /dev/null +++ b/packages/grpc-js/scripts/xds.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +nvm use 12 + +set -exu -o pipefail +[[ -f /VERSION ]] && cat /VERSION + +cd $(dirname $0) +cd .. +base=$(pwd) +npm run compile + +cd ../../.. +branch=$(git branch --all --no-color --contains "${KOKORO_GITHUB_COMMIT}" \ + | grep -v HEAD | head -1) +shopt -s extglob +branch="${branch//[[:space:]]}" +branch="${branch##remotes/origin/}" +shopt -u extglob + +git clone -b "${branch}" --single-branch --depth=1 https://github.com/grpc/grpc.git + +grpc/tools/run_tests/helper_scripts/prep_xds.sh + +# Test cases "path_matching" and "header_matching" are not included in "all", +# because not all interop clients in all languages support these new tests. +# +# TODO: remove "path_matching" and "header_matching" from --test_case after +# they are added into "all". +GRPC_TRACE=xds_client,round_robin,resolving_load_balancer GRPC_VERBOSITY=DEBUG \ + python3 grpc/tools/run_tests/run_xds_tests.py \ + --test_case="all" \ + --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="node grpc-node/packages/grpc-js/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}" \ No newline at end of file From 46c065a75bd1bf4f153edd7e938674cd46f4551a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 13:37:17 -0700 Subject: [PATCH 024/123] chmod a+x xds.sh --- packages/grpc-js/scripts/xds.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 packages/grpc-js/scripts/xds.sh diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh old mode 100644 new mode 100755 From f246833876c83f0cec62f76b58d39e832e4e4a36 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 14:00:46 -0700 Subject: [PATCH 025/123] Some test script fixes --- packages/grpc-js/scripts/xds.sh | 10 +--------- run-tests.sh | 3 +++ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index 1b6fde5d..a4c44fae 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -1,7 +1,5 @@ #!/bin/bash -nvm use 12 - set -exu -o pipefail [[ -f /VERSION ]] && cat /VERSION @@ -11,14 +9,8 @@ base=$(pwd) npm run compile cd ../../.. -branch=$(git branch --all --no-color --contains "${KOKORO_GITHUB_COMMIT}" \ - | grep -v HEAD | head -1) -shopt -s extglob -branch="${branch//[[:space:]]}" -branch="${branch##remotes/origin/}" -shopt -u extglob -git clone -b "${branch}" --single-branch --depth=1 https://github.com/grpc/grpc.git +git clone -b remotes/origin/ --single-branch --depth=1 https://github.com/grpc/grpc.git grpc/tools/run_tests/helper_scripts/prep_xds.sh diff --git a/run-tests.sh b/run-tests.sh index ca4501d0..55a08e49 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -77,6 +77,9 @@ done if [ "$OS" = "Linux" ] then + set +ex + nvm use 12 + set -ex # Run the xds interop tests only on Linux ./packages/grpc-js/scripts/xds.sh fi From bc5c29604b2b4dcfbf226b08f592292729d25d9b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 14:20:47 -0700 Subject: [PATCH 026/123] More test script fixes --- packages/grpc-js/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index a4c44fae..d39da5f6 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -10,7 +10,7 @@ npm run compile cd ../../.. -git clone -b remotes/origin/ --single-branch --depth=1 https://github.com/grpc/grpc.git +git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git grpc/tools/run_tests/helper_scripts/prep_xds.sh From f4e9b63ddf99dac3615fa43394911ed2539bafd1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 21 Aug 2020 00:10:35 -0700 Subject: [PATCH 027/123] Trace all --- packages/grpc-js/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index d39da5f6..64b9fafa 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -19,7 +19,7 @@ grpc/tools/run_tests/helper_scripts/prep_xds.sh # # TODO: remove "path_matching" and "header_matching" from --test_case after # they are added into "all". -GRPC_TRACE=xds_client,round_robin,resolving_load_balancer GRPC_VERBOSITY=DEBUG \ +GRPC_TRACE=all GRPC_VERBOSITY=DEBUG \ python3 grpc/tools/run_tests/run_xds_tests.py \ --test_case="all" \ --project_id=grpc-testing \ From 14eea7d6d27a9e5f445288c4c29aae68cf692920 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 21 Aug 2020 09:46:45 -0700 Subject: [PATCH 028/123] Add separate trace and verbosity env variables for this library --- packages/grpc-js/scripts/xds.sh | 2 +- packages/grpc-js/src/logging.ts | 33 ++++++++++++++++----------------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index 64b9fafa..e1c59e8e 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -19,7 +19,7 @@ grpc/tools/run_tests/helper_scripts/prep_xds.sh # # TODO: remove "path_matching" and "header_matching" from --test_case after # they are added into "all". -GRPC_TRACE=all GRPC_VERBOSITY=DEBUG \ +GRPC_NODE_TRACE=all GRPC_NODE_VERBOSITY=DEBUG \ python3 grpc/tools/run_tests/run_xds_tests.py \ --test_case="all" \ --project_id=grpc-testing \ 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( From 141dfeb790968359a060b4e812f35ae078c32b96 Mon Sep 17 00:00:00 2001 From: Simon Woolf Date: Fri, 21 Aug 2020 18:10:58 +0100 Subject: [PATCH 029/123] Channel#watchConnectivityState: handle infinite deadlines correctly Per https://grpc.github.io/grpc/node/grpc.html#~Deadline: "If it is a finite number, it is treated as a number of milliseconds since the Unix Epoch. If it is Infinity, the deadline will never be reached. If it is -Infinity, the deadline has already passed." --- packages/grpc-js/src/channel.ts | 40 +++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 8c369192..3195ebc2 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -120,7 +120,7 @@ export interface Channel { interface ConnectivityStateWatcher { currentState: ConnectivityState; - timer: NodeJS.Timeout; + timer: NodeJS.Timeout | null; callback: (error?: Error) => void; } @@ -417,7 +417,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(); } @@ -452,25 +454,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); } From 362b77259f4b3cd1e1f075e7470ef6cb212132ff Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 21 Aug 2020 11:02:33 -0700 Subject: [PATCH 030/123] Add more logging to the xDS interop client --- packages/grpc-js/interop/xds-interop-client.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index e056fb08..fc45b615 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -184,11 +184,13 @@ function main() { .number(['num_channels', 'qps']) .require(['fail_on_failed_rpcs', 'num_channels', 'qps', 'server', 'stats_port']) .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', @@ -211,6 +213,7 @@ function main() { if (error) { throw error; } + console.log(`Starting stats service server bound to port ${port}`); server.start(); }); } From eb849db1aaa10859fabf27661a236b665a9ef991 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 21 Aug 2020 12:47:17 -0700 Subject: [PATCH 031/123] Add a log line to the top level of xds-interop-client --- packages/grpc-js/interop/xds-interop-client.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index fc45b615..37cb0623 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -220,4 +220,6 @@ function main() { if (require.main === module) { main(); -} \ No newline at end of file +} + +console.log('Bottom of xds-interop-client'); \ No newline at end of file From 1e223048b807b6ae1bd448c0fe3625cd7dd2e880 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 21 Aug 2020 12:58:05 -0700 Subject: [PATCH 032/123] Grab xds client logs in kokoro config --- packages/grpc-js/interop/xds-interop-client.ts | 4 +--- test/kokoro/linux.cfg | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index 37cb0623..fc45b615 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -220,6 +220,4 @@ function main() { if (require.main === module) { main(); -} - -console.log('Bottom of xds-interop-client'); \ No newline at end of file +} \ No newline at end of file diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index f40e6db4..24ed01ab 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -20,5 +20,6 @@ timeout_mins: 60 action { define_artifacts { regex: "github/grpc-node/reports/**/sponge_log.xml" + regex: "github/grpc/reports/**" } } From 0e8e1adfc456a36282fa3767d525f82422b22962 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 24 Aug 2020 15:53:07 -0700 Subject: [PATCH 033/123] More test script fixes, don't run xDS tests in PR tests --- packages/grpc-js/interop/xds-interop-client.ts | 3 ++- packages/grpc-js/scripts/xds.sh | 2 +- run-tests.sh | 9 --------- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index fc45b615..f2c4cb0a 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -182,7 +182,8 @@ function main() { const argv = yargs .string(['fail_on_failed_rpcs', 'server', 'stats_port']) .number(['num_channels', 'qps']) - .require(['fail_on_failed_rpcs', 'num_channels', 'qps', 'server', 'stats_port']) + .require(['qps', 'server', 'stats_port']) + .default('num_channels', 1) .argv; console.log('Starting xDS interop client. Args: ', argv); const callStatsTracker = new CallStatsTracker(); diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index e1c59e8e..ae169eeb 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -33,4 +33,4 @@ GRPC_NODE_TRACE=all GRPC_NODE_VERBOSITY=DEBUG \ --qps={qps} \ {fail_on_failed_rpc} \ {rpcs_to_send} \ - {metadata_to_send}" \ No newline at end of file + {metadata_to_send}" diff --git a/run-tests.sh b/run-tests.sh index 55a08e49..f23475b9 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -75,15 +75,6 @@ do npm test || FAILED="true" done -if [ "$OS" = "Linux" ] -then - set +ex - nvm use 12 - set -ex - # Run the xds interop tests only on Linux - ./packages/grpc-js/scripts/xds.sh -fi - set +ex nvm use 8 set -ex From 7e35657cf1e1d0bcd408a133cd953c468a7e7ff0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 09:45:47 -0700 Subject: [PATCH 034/123] node.cluster is optional in the bootstrap file --- packages/grpc-js/src/xds-bootstrap.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js/src/xds-bootstrap.ts index b8e446b2..47e7679e 100644 --- a/packages/grpc-js/src/xds-bootstrap.ts +++ b/packages/grpc-js/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'); } @@ -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); } From 302b87183e3cc3316e2669d47495d02892140d84 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 10:05:44 -0700 Subject: [PATCH 035/123] Fix bug in bootstrap file validation --- packages/grpc-js/src/xds-bootstrap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js/src/xds-bootstrap.ts index 47e7679e..00e13d09 100644 --- a/packages/grpc-js/src/xds-bootstrap.ts +++ b/packages/grpc-js/src/xds-bootstrap.ts @@ -171,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}` From ee52de4f989c9d017165eb32641868dbcfc9dd05 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 10:54:56 -0700 Subject: [PATCH 036/123] Load proto files with json option to handle Any properly --- packages/grpc-js/src/xds-client.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 64f6a581..7580c2f4 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -105,6 +105,7 @@ function loadAdsProtos(): Promise< enums: String, defaults: true, oneofs: true, + json: true, includeDirs: [ // Paths are relative to src/build __dirname + '/../../deps/envoy-api/', From 8580204a73b7c1af46e070e3585e8cd41fb9b8d1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 11:05:22 -0700 Subject: [PATCH 037/123] Fix incorrect 'Method not implemented' error --- packages/grpc-js/src/xds-client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 7580c2f4..bd2235ab 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -641,7 +641,7 @@ class LdsState implements XdsStreamState { } } } - throw new Error('Method not implemented.'); + return null; } reportStreamError(status: StatusObject): void { From af949674da15eb3a99e82dc4cbf45e7f731f9a3a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 13:22:30 -0700 Subject: [PATCH 038/123] Add XdsClient tracers, and stream start backoff, and fix some bugs --- packages/grpc-js/src/xds-client.ts | 84 +++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index bd2235ab..5b5ed550 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -54,6 +54,7 @@ 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 } from './backoff-timeout'; const TRACER_NAME = 'xds_client'; @@ -260,6 +261,7 @@ class EdsState implements XdsStreamState { edsServiceName: string, watcher: Watcher ): void { + trace('Adding EDS watcher for edsServiceName ' + edsServiceName); let watchersEntry = this.watchers.get(edsServiceName); let addedServiceName = false; if (watchersEntry === undefined) { @@ -276,6 +278,7 @@ class EdsState implements XdsStreamState { /* 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); }); } @@ -289,6 +292,7 @@ class EdsState implements XdsStreamState { edsServiceName: string, watcher: Watcher ): void { + trace('Removing EDS watcher for edsServiceName ' + edsServiceName); const watchersEntry = this.watchers.get(edsServiceName); let removedServiceName = false; if (watchersEntry !== undefined) { @@ -342,6 +346,7 @@ class EdsState implements XdsStreamState { 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(); } @@ -352,7 +357,7 @@ class EdsState implements XdsStreamState { handleResponses(responses: ClusterLoadAssignment__Output[]) { for (const message of responses) { if (!this.validateResponse(message)) { - return 'ClusterLoadAssignment validation failed'; + return 'EDS Error: ClusterLoadAssignment validation failed'; } } this.latestResponses = responses; @@ -364,6 +369,7 @@ class EdsState implements XdsStreamState { watcher.onValidUpdate(message); } } + trace('Received EDS updates for cluster names ' + Array.from(allClusterNames)); this.handleMissingNames(allClusterNames); return null; } @@ -400,6 +406,7 @@ class CdsState implements XdsStreamState { * @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) { @@ -416,6 +423,7 @@ class CdsState implements XdsStreamState { /* 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); }); } @@ -426,6 +434,7 @@ class CdsState implements XdsStreamState { } 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) { @@ -466,14 +475,15 @@ class CdsState implements XdsStreamState { } /** - * Given a list of edsServiceNames (which may actually be the cluster name), + * 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 [edsServiceName, watcherList] of this.watchers.entries()) { - if (!allClusterNames.has(edsServiceName)) { + 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(); } @@ -484,7 +494,7 @@ class CdsState implements XdsStreamState { handleResponses(responses: Cluster__Output[]): string | null { for (const message of responses) { if (!this.validateResponse(message)) { - return 'Cluster validation failed'; + return 'CDS Error: Cluster validation failed'; } } this.latestResponses = responses; @@ -501,6 +511,7 @@ class CdsState implements XdsStreamState { watcher.onValidUpdate(message); } } + trace('Received CDS updates for cluster names ' + Array.from(allClusterNames)); this.handleMissingNames(allClusterNames); this.edsState.handleMissingNames(allEdsServiceNames); return null; @@ -535,6 +546,7 @@ class RdsState implements XdsStreamState { if (virtualHost.domains.indexOf(this.routeConfigName!) >= 0) { const route = virtualHost.routes[virtualHost.routes.length - 1]; if (route.match?.prefix === '' && route.route?.cluster) { + trace('Reporting RDS update for host ' + this.routeConfigName + ' with cluster ' + route.route.cluster); this.watcher.onValidUpdate({ methodConfig: [], loadBalancingConfig: [ @@ -546,10 +558,11 @@ class RdsState implements XdsStreamState { }, ], }); - break; + return; } } } + trace('Reporting RDS resource does not exist'); /* If none of the routes match the one we are looking for, bubble up an * error. */ this.watcher.onResourceDoesNotExist(); @@ -623,11 +636,13 @@ class LdsState implements XdsStreamState { 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! @@ -637,7 +652,7 @@ class LdsState implements XdsStreamState { // The validation rules should prevent this } } else { - return 'Listener validation failed'; + return 'LRS Error: Listener validation failed'; } } } @@ -677,11 +692,11 @@ function getResponseMessages( result.push(resource as protoLoader.AnyExtension & OutputType); } else { throw new Error( - `Invalid resource type ${ + `ADS Error: Invalid resource type ${ protoLoader.isAnyExtension(resource) ? resource['@type'] : resource.type_url - }` + }, expected ${typeUrl}` ); } } @@ -711,6 +726,9 @@ export class XdsClient { private adsState: AdsState; + private adsBackoff: BackoffTimeout; + private lrsBackoff: BackoffTimeout; + constructor( targetName: string, serviceConfigWatcher: Watcher, @@ -752,6 +770,14 @@ export class XdsClient { delete channelArgs[arg]; } channelArgs['grpc.keepalive_time_ms'] = 5000; + + this.adsBackoff = new BackoffTimeout(() => { + this.maybeStartAdsStream(); + }); + this.lrsBackoff = new BackoffTimeout(() => { + this.maybeStartLrsStream(); + }) + Promise.all([loadBootstrapInfo(), loadAdsProtos()]).then( ([bootstrapInfo, protoDefinitions]) => { if (this.hasShutdown) { @@ -770,6 +796,7 @@ export class XdsClient { ...node, client_features: ['envoy.lrs.supports_send_all_clusters'], }; + 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, createGoogleDefaultCredentials(), @@ -828,6 +855,7 @@ export class XdsClient { 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. */ @@ -836,6 +864,7 @@ export class XdsClient { 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); } } @@ -854,6 +883,9 @@ export class XdsClient { 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); @@ -864,10 +896,11 @@ export class XdsClient { ); 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(); + /* 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[] = [ @@ -889,6 +922,11 @@ export class XdsClient { * 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); } @@ -953,8 +991,17 @@ export class XdsClient { 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 !== @@ -970,7 +1017,7 @@ export class XdsClient { const loadReportingIntervalMs = Number.parseInt(message.load_reporting_interval!.seconds) * 1000 + message.load_reporting_interval!.nanos / 1_000_000; - setInterval(() => { + this.statsTimer = setInterval(() => { this.sendStats(); }, loadReportingIntervalMs); } @@ -982,10 +1029,11 @@ export class XdsClient { ); this.lrsCall = null; clearInterval(this.statsTimer); - /* 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(); + /* 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(); + } }); this.lrsCall.write({ node: this.lrsNode!, From 36a6580921ff5f2db0ded02a1d49578450ef8592 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 13:49:28 -0700 Subject: [PATCH 039/123] Add more XdsClient tracing --- packages/grpc-js/src/xds-client.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 5b5ed550..1af5d010 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -357,6 +357,7 @@ class EdsState implements XdsStreamState { 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'; } } @@ -494,6 +495,7 @@ class CdsState implements XdsStreamState { 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'; } } @@ -559,16 +561,19 @@ class RdsState implements XdsStreamState { ], }); return; + } else { + trace('Discarded matching route with prefix ' + route.match?.prefix + ' and cluster ' + route.route?.cluster); } } } - trace('Reporting RDS resource does not exist'); + 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) { @@ -627,6 +632,7 @@ class LdsState implements XdsStreamState { } 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)) { @@ -652,6 +658,7 @@ class LdsState implements XdsStreamState { // The validation rules should prevent this } } else { + trace('LRS validation error for message ' + JSON.stringify(message)); return 'LRS Error: Listener validation failed'; } } @@ -965,6 +972,7 @@ export class XdsClient { } 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, From 240444623468754e08fa8dbc3914b174568716de Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 14:10:54 -0700 Subject: [PATCH 040/123] Fix RDS domain search --- packages/grpc-js/src/xds-client.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 1af5d010..bfeb4ed5 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -535,6 +535,7 @@ class RdsState implements XdsStreamState { private routeConfigName: string | null = null; constructor( + private targetName: string, private watcher: Watcher, private updateResouceNames: () => void ) {} @@ -545,10 +546,10 @@ class RdsState implements XdsStreamState { handleSingleMessage(message: RouteConfiguration__Output) { for (const virtualHost of message.virtual_hosts) { - if (virtualHost.domains.indexOf(this.routeConfigName!) >= 0) { + 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.routeConfigName + ' with cluster ' + route.route.cluster); + trace('Reporting RDS update for host ' + this.targetName + ' with cluster ' + route.route.cluster); this.watcher.onValidUpdate({ methodConfig: [], loadBalancingConfig: [ @@ -747,7 +748,7 @@ export class XdsClient { const cdsState = new CdsState(edsState, () => { this.updateNames(CDS_TYPE_URL); }); - const rdsState = new RdsState(serviceConfigWatcher, () => { + const rdsState = new RdsState(targetName, serviceConfigWatcher, () => { this.updateNames(RDS_TYPE_URL); }); const ldsState = new LdsState(targetName, rdsState); From 197cc84e7ac150bfe605e7cbf4a7bbc5dc724f64 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 27 Aug 2020 11:05:54 -0700 Subject: [PATCH 041/123] Add more tracers, fix onResourceDoesNotExist handling --- .../grpc-js/interop/xds-interop-client.ts | 2 ++ packages/grpc-js/src/load-balancer-cds.ts | 14 +++++++++++ .../src/load-balancer-child-handler.ts | 2 ++ packages/grpc-js/src/load-balancer-eds.ts | 17 +++++++++++++- .../grpc-js/src/load-balancer-priority.ts | 18 ++++++++++++++- .../src/load-balancer-weighted-target.ts | 23 ++++++++++++++++--- packages/grpc-js/src/resolver-xds.ts | 13 ++++++++++- 7 files changed, 83 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index f2c4cb0a..c33c5b38 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -200,7 +200,9 @@ function main() { 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'}); diff --git a/packages/grpc-js/src/load-balancer-cds.ts b/packages/grpc-js/src/load-balancer-cds.ts index 82346978..01cc4c62 100644 --- a/packages/grpc-js/src/load-balancer-cds.ts +++ b/packages/grpc-js/src/load-balancer-cds.ts @@ -34,6 +34,14 @@ import { ConnectivityState } from './channel'; import { UnavailablePicker } from './picker'; import { Status } from './constants'; import { Metadata } from './metadata'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'cds_balancer'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'cds'; @@ -70,6 +78,7 @@ export class CdsLoadBalancer implements LoadBalancer { * Otherwise, if the field is omitted, load reporting is disabled. */ edsConfig.lrsLoadReportingServerName = ''; } + trace('Child update EDS config: ' + JSON.stringify(edsConfig)); this.childBalancer.updateAddressList( [], { name: 'eds', eds: edsConfig }, @@ -82,6 +91,8 @@ export class CdsLoadBalancer implements LoadBalancer { this.watcher ); 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: (status) => { if (this.latestCdsUpdate === null) { @@ -104,11 +115,14 @@ export class CdsLoadBalancer implements LoadBalancer { attributes: { [key: string]: unknown } ): void { if (!isCdsLoadBalancingConfig(lbConfig)) { + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); return; } if (!(attributes.xdsClient instanceof XdsClient)) { + trace('Discarding address list update missing xdsClient attribute'); return; } + trace('Received update with config ' + JSON.stringify(lbConfig)); this.xdsClient = attributes.xdsClient; this.latestAttributes = attributes; diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index 158108f0..b0044d12 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -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 index 57aac25b..c0d90e8e 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -21,7 +21,7 @@ import { registerLoadBalancerType, getFirstUsableConfig, } from './load-balancer'; -import { SubchannelAddress } from './subchannel'; +import { SubchannelAddress, subchannelAddressToString } from './subchannel'; import { LoadBalancingConfig, isEdsLoadBalancingConfig, @@ -40,6 +40,14 @@ import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; import { LocalitySubchannelAddress } from './load-balancer-priority'; import { Status } from './constants'; import { Metadata } from './metadata'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'eds_balancer'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'eds'; @@ -136,6 +144,8 @@ export class EdsLoadBalancer implements LoadBalancer { this.watcher ); 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) { @@ -356,6 +366,8 @@ export class EdsLoadBalancer implements LoadBalancer { priorities: newPriorityNames.filter((value) => value !== undefined), }, }; + trace('Child update addresses: ' + addressList.map(address => '(' + subchannelAddressToString(address) + ' path=' + address.localityPath + ')')); + trace('Child update service config: ' + JSON.stringify(childConfig)); this.childBalancer.updateAddressList( addressList, childConfig, @@ -372,11 +384,14 @@ export class EdsLoadBalancer implements LoadBalancer { attributes: { [key: string]: unknown } ): void { if (!isEdsLoadBalancingConfig(lbConfig)) { + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); return; } if (!(attributes.xdsClient instanceof XdsClient)) { + trace('Discarding address list update missing xdsClient attribute'); return; } + trace('Received update with config: ' + JSON.stringify(lbConfig)); this.lastestConfig = lbConfig; this.latestAttributes = attributes; this.xdsClient = attributes.xdsClient; diff --git a/packages/grpc-js/src/load-balancer-priority.ts b/packages/grpc-js/src/load-balancer-priority.ts index d3070715..6539e4b4 100644 --- a/packages/grpc-js/src/load-balancer-priority.ts +++ b/packages/grpc-js/src/load-balancer-priority.ts @@ -21,7 +21,7 @@ import { getFirstUsableConfig, registerLoadBalancerType, } from './load-balancer'; -import { SubchannelAddress } from './subchannel'; +import { SubchannelAddress, subchannelAddressToString } from './subchannel'; import { LoadBalancingConfig, isPriorityLoadBalancingConfig, @@ -32,6 +32,14 @@ import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; import { ChannelOptions } from './channel-options'; import { Status } from './constants'; import { Metadata } from './metadata'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'priority'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'priority'; @@ -222,6 +230,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 +245,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 || @@ -369,6 +382,7 @@ export class PriorityLoadBalancer implements LoadBalancer { ): void { if (!isPriorityLoadBalancingConfig(lbConfig)) { // Reject a config of the wrong type + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); return; } const priorityConfig = lbConfig.priority; @@ -416,6 +430,7 @@ export class PriorityLoadBalancer implements LoadBalancer { 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 +448,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(); } } diff --git a/packages/grpc-js/src/load-balancer-weighted-target.ts b/packages/grpc-js/src/load-balancer-weighted-target.ts index e8a5fe65..2da67e7f 100644 --- a/packages/grpc-js/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js/src/load-balancer-weighted-target.ts @@ -16,7 +16,7 @@ */ import { LoadBalancer, ChannelControlHelper, getFirstUsableConfig, registerLoadBalancerType } from "./load-balancer"; -import { SubchannelAddress } from "./subchannel"; +import { SubchannelAddress, subchannelAddressToString } from "./subchannel"; import { LoadBalancingConfig, WeightedTarget, isWeightedTargetLoadBalancingConfig } from "./load-balancing-config"; import { Picker, PickResult, PickArgs, QueuePicker, UnavailablePicker } from "./picker"; import { ConnectivityState } from "./channel"; @@ -24,6 +24,14 @@ import { ChildLoadBalancerHandler } from "./load-balancer-child-handler"; import { Status } from "./constants"; import { Metadata } from "./metadata"; import { isLocalitySubchannelAddress, LocalitySubchannelAddress } from "./load-balancer-priority"; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'weighted_target'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'weighted_target'; @@ -116,6 +124,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(); @@ -239,12 +248,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)) { // Reject a config of the wrong type + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); return; } @@ -252,7 +266,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 @@ -284,12 +298,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(); } } diff --git a/packages/grpc-js/src/resolver-xds.ts b/packages/grpc-js/src/resolver-xds.ts index e92fddff..38cc37a6 100644 --- a/packages/grpc-js/src/resolver-xds.ts +++ b/packages/grpc-js/src/resolver-xds.ts @@ -19,9 +19,16 @@ import { GrpcUri, uriToString } from './uri-parser'; import { XdsClient } from './xds-client'; import { ServiceConfig } from './service-config'; import { StatusObject } from './call-stream'; -import { Status } from './constants'; +import { Status, LogVerbosity } from './constants'; import { Metadata } from './metadata'; import { ChannelOptions } from './channel-options'; +import * as logging from './logging'; + +const TRACER_NAME = 'xds_resolver'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} class XdsResolver implements Resolver { private resolutionStarted = false; @@ -47,10 +54,12 @@ class XdsResolver implements Resolver { // Wait until updateResolution is called once to start the xDS requests if (!this.resolutionStarted) { this.resolutionStarted = true; + trace('Starting resolution for target ' + this.target); const xdsClient = new XdsClient( this.target.path, { onValidUpdate: (update: ServiceConfig) => { + trace('Resolved service config for target ' + this.target + ': ' + JSON.stringify(update)); this.hasReportedSuccess = true; this.listener.onSuccessfulResolution([], update, null, { xdsClient: xdsClient, @@ -60,10 +69,12 @@ class XdsResolver implements Resolver { /* 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 ' + this.target + ' due to xDS client transient error ' + error.details); this.reportResolutionError(); } }, onResourceDoesNotExist: () => { + trace('Resolution error for target ' + this.target + ': resource does not exist'); this.reportResolutionError(); }, }, From 665632f48034f383b09704d82ec593624f4c0c20 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 27 Aug 2020 12:47:53 -0700 Subject: [PATCH 042/123] Add more keepalive logging --- packages/grpc-js/src/subchannel.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 736562a6..c90df85e 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'; @@ -263,6 +263,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); @@ -405,14 +406,14 @@ 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}` + ); } trace( this.subchannelAddressString + @@ -689,7 +690,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); } From c83d5a7c4deb5ffa7cfbeab3876f934c32bbe2c3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 27 Aug 2020 13:23:07 -0700 Subject: [PATCH 043/123] Fix keepalive ping timing, change some trace logs --- packages/grpc-js/src/subchannel.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index c90df85e..394124f7 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -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; @@ -278,7 +282,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() { @@ -584,7 +589,7 @@ export class Subchannel { } callRef() { - trace( + refTrace( this.subchannelAddressString + ' callRefcount ' + this.callRefcount + @@ -601,7 +606,7 @@ export class Subchannel { } callUnref() { - trace( + refTrace( this.subchannelAddressString + ' callRefcount ' + this.callRefcount + @@ -619,7 +624,7 @@ export class Subchannel { } ref() { - trace( + refTrace( this.subchannelAddressString + ' refcount ' + this.refcount + @@ -630,7 +635,7 @@ export class Subchannel { } unref() { - trace( + refTrace( this.subchannelAddressString + ' refcount ' + this.refcount + From 1a47f78f4f5abcf78e29b535fdab4c9238cb6f7a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 27 Aug 2020 14:17:29 -0700 Subject: [PATCH 044/123] Fix some trace logs, increase XdsClient keepalive interval --- packages/grpc-js/src/resolver-xds.ts | 8 ++++---- packages/grpc-js/src/subchannel.ts | 2 +- packages/grpc-js/src/xds-client.ts | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/resolver-xds.ts b/packages/grpc-js/src/resolver-xds.ts index 38cc37a6..297c6c3f 100644 --- a/packages/grpc-js/src/resolver-xds.ts +++ b/packages/grpc-js/src/resolver-xds.ts @@ -54,12 +54,12 @@ class XdsResolver implements Resolver { // Wait until updateResolution is called once to start the xDS requests if (!this.resolutionStarted) { this.resolutionStarted = true; - trace('Starting resolution for target ' + this.target); + trace('Starting resolution for target ' + uriToString(this.target)); const xdsClient = new XdsClient( this.target.path, { onValidUpdate: (update: ServiceConfig) => { - trace('Resolved service config for target ' + this.target + ': ' + JSON.stringify(update)); + trace('Resolved service config for target ' + uriToString(this.target) + ': ' + JSON.stringify(update)); this.hasReportedSuccess = true; this.listener.onSuccessfulResolution([], update, null, { xdsClient: xdsClient, @@ -69,12 +69,12 @@ class XdsResolver implements Resolver { /* 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 ' + this.target + ' due to xDS client transient error ' + error.details); + trace('Resolution error for target ' + uriToString(this.target) + ' due to xDS client transient error ' + error.details); this.reportResolutionError(); } }, onResourceDoesNotExist: () => { - trace('Resolution error for target ' + this.target + ': resource does not exist'); + trace('Resolution error for target ' + uriToString(this.target) + ': resource does not exist'); this.reportResolutionError(); }, }, diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 394124f7..b7f2a118 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -417,7 +417,7 @@ export class Subchannel { ); 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}` + `Connection to ${uriToString(this.channelTarget)} at ${this.subchannelAddressString} rejected by server because of excess pings. Increasing ping interval to ${this.keepaliveTimeMs} ms` ); } trace( diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index bfeb4ed5..327f2156 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -777,7 +777,8 @@ export class XdsClient { for (const arg of channelArgsToRemove) { delete channelArgs[arg]; } - channelArgs['grpc.keepalive_time_ms'] = 5000; + // 5 minutes + channelArgs['grpc.keepalive_time_ms'] = 5 * 60 * 1000; this.adsBackoff = new BackoffTimeout(() => { this.maybeStartAdsStream(); From 82037fcdaffe478f1f1cfdbb3caeae9a456b9370 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 27 Aug 2020 15:54:05 -0700 Subject: [PATCH 045/123] Add error logging to xDS interop client --- .../grpc-js/interop/xds-interop-client.ts | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index c33c5b38..3a741848 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -39,7 +39,7 @@ const loadedProto = grpc.loadPackageDefinition(packageDefinition) as unknown as interface CallEndNotifier { onCallSucceeded(peerName: string): void; - onCallFailed(): void; + onCallFailed(message: string): void; } class CallSubscriber { @@ -47,6 +47,7 @@ class CallSubscriber { private callsSucceededByPeer: {[key: string]: number} = {}; private callsSucceeded = 0; private callsFinished = 0; + private failureMessageCount: Map = new Map(); constructor(private callGoal: number, private onFinished: () => void) {} @@ -56,6 +57,10 @@ class CallSubscriber { private maybeOnFinished() { if (this.callsFinished == this.callGoal) { + console.log(`Out of a total of ${this.callsFinished} calls, ${this.callsSucceeded} succeeded`); + for (const [message, count] of this.failureMessageCount) { + console.log(`${count} failed with the message ${message}`); + } this.onFinished(); } } @@ -70,8 +75,9 @@ class CallSubscriber { this.callsFinished += 1; this.maybeOnFinished(); } - addCallFailed(): void { + addCallFailed(message: string): void { this.callsFinished += 1; + this.failureMessageCount.set(message, (this.failureMessageCount.get(message) ?? 0) + 1); this.maybeOnFinished(); } @@ -125,9 +131,9 @@ class CallStatsTracker { subscriber.addCallSucceeded(peerName); } }, - onCallFailed: () => { + onCallFailed: (message: string) => { for (const subscriber of callSubscribers) { - subscriber.addCallFailed(); + subscriber.addCallFailed(message); } } } @@ -150,12 +156,12 @@ function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpc } completed = true; completedWithError = true; - notifier.onCallFailed(); + notifier.onCallFailed(error.message); } else { anyCallSucceeded = true; if (gotMetadata) { if (hostname === null) { - notifier.onCallFailed() + notifier.onCallFailed('Hostname omitted from call metadata'); } else { notifier.onCallSucceeded(hostname); } @@ -167,7 +173,7 @@ function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpc gotMetadata = true; if (completed && !completedWithError) { if (hostname === null) { - notifier.onCallFailed(); + notifier.onCallFailed('Hostname omitted from call metadata'); } else { notifier.onCallSucceeded(hostname); } From 597fc1c57bac0c83e2864940007643a644fa7990 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 27 Aug 2020 18:14:03 -0700 Subject: [PATCH 046/123] Use the same channel for ADS and LRS clients --- packages/grpc-js/src/channel-options.ts | 2 +- packages/grpc-js/src/xds-client.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 8c4756ec..ee4833b4 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -33,7 +33,7 @@ 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; + [key: string]: any; } /** diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 327f2156..1c4f149b 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -816,7 +816,7 @@ export class XdsClient { this.lrsClient = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( bootstrapInfo.xdsServers[0].serverUri, createGoogleDefaultCredentials(), - channelArgs + {channelOverride: this.adsClient.getChannel()} ); this.maybeStartLrsStream(); }, From 8269fd4bca21b428bc50c8d0b373aa235ead2719 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Aug 2020 09:50:33 -0700 Subject: [PATCH 047/123] priority: improve tracing, cancel failover timer when selecting child --- packages/grpc-js/src/load-balancer-priority.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-js/src/load-balancer-priority.ts b/packages/grpc-js/src/load-balancer-priority.ts index 6539e4b4..74f2e978 100644 --- a/packages/grpc-js/src/load-balancer-priority.ts +++ b/packages/grpc-js/src/load-balancer-priority.ts @@ -111,6 +111,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); @@ -118,7 +119,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, @@ -308,6 +311,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() From 338941d6642228381b17d76d6ba15f761d79d207 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Aug 2020 10:06:57 -0700 Subject: [PATCH 048/123] Add more LRS tracing --- packages/grpc-js/src/xds-client.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 1c4f149b..62f14f61 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -1027,7 +1027,9 @@ export class XdsClient { 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(() => { + trace('Sending LRS stats'); this.sendStats(); }, loadReportingIntervalMs); } From 60bc11285b5da059e641eb9e5b957b9be305014e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Aug 2020 10:43:16 -0700 Subject: [PATCH 049/123] Send buffered stats when starting LRS stream --- packages/grpc-js/src/xds-client.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 62f14f61..39c01646 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -1029,7 +1029,6 @@ export class XdsClient { message.load_reporting_interval!.nanos / 1_000_000; trace('Received LRS request with load reporting interval ' + loadReportingIntervalMs + ' ms'); this.statsTimer = setInterval(() => { - trace('Sending LRS stats'); this.sendStats(); }, loadReportingIntervalMs); } @@ -1047,15 +1046,16 @@ export class XdsClient { this.maybeStartLrsStream(); } }); - this.lrsCall.write({ - node: this.lrsNode!, - }); + /* 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 }, From b9962feff080c2ef2aa91e14bdb4044a77666853 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Aug 2020 11:17:52 -0700 Subject: [PATCH 050/123] Add more interop client logging --- packages/grpc-js/interop/xds-interop-client.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index 3a741848..d9d7c441 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -52,20 +52,18 @@ class CallSubscriber { constructor(private callGoal: number, private onFinished: () => void) {} addCallStarted(): void { + console.log('Call started'); this.callsStarted += 1; } private maybeOnFinished() { if (this.callsFinished == this.callGoal) { - console.log(`Out of a total of ${this.callsFinished} calls, ${this.callsSucceeded} succeeded`); - for (const [message, count] of this.failureMessageCount) { - console.log(`${count} failed with the message ${message}`); - } this.onFinished(); } } addCallSucceeded(peerName: string): void { + console.log(`Call to ${peerName} succeeded`); if (peerName in this.callsSucceededByPeer) { this.callsSucceededByPeer[peerName] += 1; } else { @@ -76,6 +74,7 @@ class CallSubscriber { this.maybeOnFinished(); } addCallFailed(message: string): void { + console.log(`Call failed with message ${message}`); this.callsFinished += 1; this.failureMessageCount.set(message, (this.failureMessageCount.get(message) ?? 0) + 1); this.maybeOnFinished(); @@ -86,6 +85,10 @@ class CallSubscriber { } getFinalStats(): LoadBalancerStatsResponse { + 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 From 5827b3e01d2c95746bcc699ab3ce5f844e1100a4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Aug 2020 11:49:03 -0700 Subject: [PATCH 051/123] Reset saved LRS settings when the LRS stream ends --- packages/grpc-js/src/xds-client.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 39c01646..0b1fa7b9 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -1039,6 +1039,7 @@ export class XdsClient { '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. */ From 36db24e39f0931a5c16a2c9add6350df45b84a29 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Aug 2020 12:50:53 -0700 Subject: [PATCH 052/123] Set a deadline on outgoing requests in the xds interop client --- packages/grpc-js/interop/xds-interop-client.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index d9d7c441..949da238 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -37,6 +37,8 @@ const packageDefinition = protoLoader.loadSync('grpc/testing/test.proto', { const loadedProto = grpc.loadPackageDefinition(packageDefinition) as unknown as ProtoGrpcType; +const REQUEST_TIMEOUT_SEC = 20; + interface CallEndNotifier { onCallSucceeded(peerName: string): void; onCallFailed(message: string): void; @@ -151,7 +153,9 @@ function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpc let hostname: string | null = null; let completed: boolean = false; let completedWithError: boolean = false; - const call = client.emptyCall({}, (error, value) => { + 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'); From c536178c675aa3527aa8cd366a274009ed7a050c Mon Sep 17 00:00:00 2001 From: WK Date: Sat, 29 Aug 2020 19:05:42 +0800 Subject: [PATCH 053/123] Fixed connectivity to Google PubSub over proxy Latest version has caused @google-cloud/pubsub fail to connect over a proxy connection. Snapshot of error: 2020-08-29T10:52:45.340Z | proxy | Successfully connected to pubsub.googleapis.c om:443 through proxy 172.16.52.252:443 2020-08-29T10:52:45.370Z | subchannel | 172.16.52.252:443 CONNECTING -> TRANSIEN T_FAILURE 2020-08-29T10:52:45.372Z | pick_first | CONNECTING -> TRANSIENT_FAILURE 2020-08-29T10:52:45.373Z | resolving_load_balancer | dns:172.16.52.252:443 CONNE CTING -> TRANSIENT_FAILURE 2020-08-29T10:52:45.375Z | channel | Pick result: TRANSIENT_FAILURE subchannel: undefined status: 14 No connection established 2020-08-29T10:52:45.377Z | call_stream | [11] cancelWithStatus code: 14 details: "No connection established" 2020-08-29T10:52:45.379Z | call_stream | [11] ended with status: code=14 details ="No connection established" 2020-08-29T10:52:45.381Z | connectivity_state | dns:172.16.52.252:443 CONNECTING -> TRANSIENT_FAILURE Before proposed fix: static getDefaultAuthority(target) { return target.path; // this returns "pubsub.googleapis.com:443" } After proposed fix: static getDefaultAuthority(target) { const hostPort = uri_parser_1.splitHostPort(target.path); // target.path is "pubsub.googleapis.com:443" if (hostPort !== null) { return hostPort.host; // this returns "pubsub.googleapis.com" } else { throw new Error(`Failed to parse target ${uri_parser_1.uriToString(target)}`); } } --- packages/grpc-js/src/resolver-dns.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 2db8a5e4..3f28254b 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -268,7 +268,13 @@ class DnsResolver implements Resolver { * @param target */ static getDefaultAuthority(target: GrpcUri): string { - return target.path; + const hostPort = uri_parser_1.splitHostPort(target.path); + if (hostPort !== null) { + return hostPort.host; + } + else { + throw new Error(`Failed to parse target ${uri_parser_1.uriToString(target)}`); + } } } From 6f3db6f4d89c8fcd308e700374c69aadf864b19f Mon Sep 17 00:00:00 2001 From: WK Date: Sun, 30 Aug 2020 14:49:54 +0800 Subject: [PATCH 054/123] Update http_proxy.ts --- packages/grpc-js/src/http_proxy.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 8411e117..e3fdee05 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -215,8 +215,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 !== null) ? hostPort.host : targetPath; + const cts = tls.connect( { host: remoteHost, From 08350ec0efe84eabbb3e950fcdce6d470fe6c555 Mon Sep 17 00:00:00 2001 From: WK Date: Sun, 30 Aug 2020 14:52:20 +0800 Subject: [PATCH 055/123] Update subchannel.ts --- packages/grpc-js/src/subchannel.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 736562a6..87805246 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -467,11 +467,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 !== null) ? hostPort.host : targetPath; } } } From 6a99983ed110433cedd432c8f020b123aaaf4fd7 Mon Sep 17 00:00:00 2001 From: WK Date: Sun, 30 Aug 2020 14:56:23 +0800 Subject: [PATCH 056/123] Undo changes. --- packages/grpc-js/src/resolver-dns.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 3f28254b..2db8a5e4 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -268,13 +268,7 @@ class DnsResolver implements Resolver { * @param target */ static getDefaultAuthority(target: GrpcUri): string { - const hostPort = uri_parser_1.splitHostPort(target.path); - if (hostPort !== null) { - return hostPort.host; - } - else { - throw new Error(`Failed to parse target ${uri_parser_1.uriToString(target)}`); - } + return target.path; } } From 62bd1cab6875d1127268db46d75092ffdbc59090 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 31 Aug 2020 09:55:29 -0700 Subject: [PATCH 057/123] Add granular verbosity option to xDS interop client --- .../grpc-js/interop/xds-interop-client.ts | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index 949da238..3009541c 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -39,6 +39,8 @@ const loadedProto = grpc.loadPackageDefinition(packageDefinition) as unknown as 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; @@ -54,7 +56,9 @@ class CallSubscriber { constructor(private callGoal: number, private onFinished: () => void) {} addCallStarted(): void { - console.log('Call started'); + if (VERBOSITY >= 2) { + console.log('Call started'); + } this.callsStarted += 1; } @@ -65,7 +69,9 @@ class CallSubscriber { } addCallSucceeded(peerName: string): void { - console.log(`Call to ${peerName} succeeded`); + if (VERBOSITY >= 2) { + console.log(`Call to ${peerName} succeeded`); + } if (peerName in this.callsSucceededByPeer) { this.callsSucceededByPeer[peerName] += 1; } else { @@ -76,7 +82,9 @@ class CallSubscriber { this.maybeOnFinished(); } addCallFailed(message: string): void { - console.log(`Call failed with message ${message}`); + 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(); @@ -87,9 +95,11 @@ class CallSubscriber { } getFinalStats(): LoadBalancerStatsResponse { - 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}`); + 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, From 148b273f196ee5bdfc4a6459d07a5d6440edc0c9 Mon Sep 17 00:00:00 2001 From: WK Date: Tue, 1 Sep 2020 01:28:53 +0800 Subject: [PATCH 058/123] Update http_proxy.ts --- packages/grpc-js/src/http_proxy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index e3fdee05..84e29a50 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -217,7 +217,7 @@ export function getProxiedConnection( * See https://github.com/grpc/grpc-node/pull/1369 for more info. */ const targetPath = getDefaultAuthority(parsedTarget); const hostPort = splitHostPort(targetPath); - const remoteHost = (hostPort !== null) ? hostPort.host : targetPath; + const remoteHost = hostPort?.host ?? targetPath; const cts = tls.connect( { From 7fc0035f7f84646269fd391f9cb80ab404f5319a Mon Sep 17 00:00:00 2001 From: WK Date: Tue, 1 Sep 2020 01:30:35 +0800 Subject: [PATCH 059/123] Update subchannel.ts --- packages/grpc-js/src/subchannel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 87805246..a8c81df8 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -473,7 +473,7 @@ export class Subchannel { } ); const hostPort = splitHostPort(targetPath); - connectionOptions.servername = (hostPort !== null) ? hostPort.host : targetPath; + connectionOptions.servername = hostPort?.host ?? : targetPath; } } } From 158d0dd99f9997e2ad34cec2fc756ae21bddc5f9 Mon Sep 17 00:00:00 2001 From: WK Date: Tue, 1 Sep 2020 01:40:14 +0800 Subject: [PATCH 060/123] Update subchannel.ts --- packages/grpc-js/src/subchannel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index a8c81df8..3be6dd0a 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -473,7 +473,7 @@ export class Subchannel { } ); const hostPort = splitHostPort(targetPath); - connectionOptions.servername = hostPort?.host ?? : targetPath; + connectionOptions.servername = hostPort?.host ?? targetPath; } } } From 38e988ea03bd76ab4002e69903d43d3fe1b31fd9 Mon Sep 17 00:00:00 2001 From: Slavo Vojacek Date: Mon, 31 Aug 2020 20:34:14 +0100 Subject: [PATCH 061/123] fix(grpc-js): Add support for impl type to server.addService --- packages/grpc-js/src/server.ts | 11 ++++++++--- packages/grpc-js/test/test-server.ts | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 8d8952e8..673e913d 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -144,9 +144,14 @@ export class Server { throw new Error('Not implemented. Use addService() instead'); } - addService( - service: ServiceDefinition, - implementation: UntypedServiceImplementation + addService< + ImplementationType extends Record< + string, + UntypedHandleCall + > = UntypedServiceImplementation + >( + service: ServiceDefinition, + implementation: ImplementationType ): void { if (this.started === true) { throw new Error("Can't add a service to a started server."); diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 434efbbc..f8b13b30 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -181,7 +181,7 @@ describe('Server', () => { const server = new Server(); assert.throws(() => { - server.addService({}, dummyImpls); + server.addService({} as any, dummyImpls); }, /Cannot add an empty service to a server/); }); From 286c81a9240f30adb4c4b58252fdcaaba8c1f915 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 31 Aug 2020 14:04:53 -0700 Subject: [PATCH 062/123] Handle endpoint health_status, improve some logging --- packages/grpc-js/src/load-balancer-eds.ts | 41 ++++++++++++++--------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index c0d90e8e..2e606fcf 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -217,6 +217,10 @@ export class EdsLoadBalancer implements LoadBalancer { 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 @@ -225,12 +229,7 @@ export class EdsLoadBalancer implements LoadBalancer { * 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( + 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. */ @@ -241,15 +240,22 @@ export class EdsLoadBalancer implements LoadBalancer { }; } ); - localityArray.push({ - locality: endpoint.locality!, - addresses: addresses, - weight: endpoint.load_balancing_weight?.value ?? 0, - }); - newLocalityPriorities.set( - localityToName(endpoint.locality!), - endpoint.priority - ); + 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 ?? 0, + }); + newLocalityPriorities.set( + localityToName(endpoint.locality!), + endpoint.priority + ); + } } const newPriorityNames: string[] = []; @@ -266,6 +272,7 @@ export class EdsLoadBalancer implements LoadBalancer { * - 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; } @@ -367,7 +374,9 @@ export class EdsLoadBalancer implements LoadBalancer { }, }; trace('Child update addresses: ' + addressList.map(address => '(' + subchannelAddressToString(address) + ' path=' + address.localityPath + ')')); - trace('Child update service config: ' + JSON.stringify(childConfig)); + for (const [childName, child] of childConfig.priority.priorities.entries()) { + trace('Child update priority config: ' + childName + ' -> ' + JSON.stringify(child)); + } this.childBalancer.updateAddressList( addressList, childConfig, From 2c98a3d3f9728104498566a2f25bdf857fae99df Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 31 Aug 2020 15:18:00 -0700 Subject: [PATCH 063/123] More EDS logging, and improved weight handling --- packages/grpc-js/src/load-balancer-eds.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 2e606fcf..ccc56e9f 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -135,6 +135,7 @@ export class EdsLoadBalancer implements LoadBalancer { }); this.watcher = { onValidUpdate: (update) => { + trace('Received EDS update for ' + this.edsServiceName + ': ' + JSON.stringify(update)); this.latestEdsUpdate = update; this.updateChild(); }, @@ -229,6 +230,9 @@ export class EdsLoadBalancer implements LoadBalancer { * 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 @@ -249,7 +253,7 @@ export class EdsLoadBalancer implements LoadBalancer { localityArray.push({ locality: endpoint.locality!, addresses: addresses, - weight: endpoint.load_balancing_weight?.value ?? 0, + weight: endpoint.load_balancing_weight.value, }); newLocalityPriorities.set( localityToName(endpoint.locality!), @@ -374,7 +378,8 @@ export class EdsLoadBalancer implements LoadBalancer { }, }; trace('Child update addresses: ' + addressList.map(address => '(' + subchannelAddressToString(address) + ' path=' + address.localityPath + ')')); - for (const [childName, child] of childConfig.priority.priorities.entries()) { + trace('Child update priority list: ' + childConfig.priority.priorities); + for (const [childName, child] of childConfig.priority.children) { trace('Child update priority config: ' + childName + ' -> ' + JSON.stringify(child)); } this.childBalancer.updateAddressList( From 5e42be1b3485949ccecd6b9068d603b298177e17 Mon Sep 17 00:00:00 2001 From: Algin Maduro Date: Tue, 1 Sep 2020 12:59:07 +0200 Subject: [PATCH 064/123] fix: preserve original error code if present --- packages/grpc-js/src/server-call.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 3ff4c55e..7c740013 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -743,7 +743,10 @@ export class Http2ServerCallStream< // Ignore any remaining messages when errors occur. this.bufferedMessages.length = 0; - err.code = Status.INTERNAL; + if(!err.code){ + err.code = Status.INTERNAL; + } + readable.emit('error', err); } From aaee068a6972d9ff18db8fc19c460b02b1a0b5ff Mon Sep 17 00:00:00 2001 From: Algin Maduro Date: Tue, 1 Sep 2020 13:28:23 +0200 Subject: [PATCH 065/123] fix: add addition check if the provided code is valid gRPC code --- packages/grpc-js/src/server-call.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 7c740013..fad0eddb 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -739,15 +739,24 @@ export class Http2ServerCallStream< } else { this.messagesToPush.push(deserialized); } - } catch (err) { + } catch (error) { // Ignore any remaining messages when errors occur. this.bufferedMessages.length = 0; - if(!err.code){ - err.code = Status.INTERNAL; + 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', err); + + readable.emit('error', error); } this.isPushPending = false; From b2d89820a3ba920fc5a4ea35dad63a857b546346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20=C5=A0mol=C3=ADk?= Date: Tue, 1 Sep 2020 14:24:25 +0200 Subject: [PATCH 066/123] Fix ClientOptions types Remove index signature from ChannelOptions to fix intersection error described in #1558 which causes issues on using ClientOptions direct fields with TypeScript. Removing of index signature required few minor changes: - adding few constant types that were used throughout the app - using `as const` assertion in xds-client - using not-so-great type cast in channelOptionsEqual Alternative solution would be removing the index signature from ChannelOptions explicitly in ClientOptions definition, which is not trivial and probably calls for a generic type helper. See: https://github.com/grpc/grpc-node/issues/1558 Fixes: #1558 --- packages/grpc-js/src/channel-options.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 8c4756ec..f316a58a 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -33,7 +33,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; } /** From 0d1d5a12fa1e3ee444db6929e9f7707b6bde5bc1 Mon Sep 17 00:00:00 2001 From: Slavo Vojacek Date: Wed, 2 Sep 2020 16:05:10 +0100 Subject: [PATCH 067/123] chore(Typings): Update types --- packages/grpc-js/src/server.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 673e913d..9b5f3af8 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -145,10 +145,9 @@ export class Server { } addService< - ImplementationType extends Record< - string, - UntypedHandleCall - > = UntypedServiceImplementation + ImplementationType extends { + readonly [index in keyof ImplementationType]: UntypedHandleCall; + } >( service: ServiceDefinition, implementation: ImplementationType @@ -166,7 +165,7 @@ export class Server { throw new Error('addService() requires two objects as arguments'); } - const serviceKeys = Object.keys(service); + const serviceKeys = Object.keys(service) as Array; if (serviceKeys.length === 0) { throw new Error('Cannot add an empty service to a server'); @@ -194,13 +193,13 @@ export class Server { let impl; if (implFn === undefined && typeof attrs.originalName === 'string') { - implFn = implementation[attrs.originalName]; + implFn = implementation[attrs.originalName as keyof ImplementationType]; } if (implFn !== undefined) { - impl = implFn.bind(implementation); + impl = implFn.bind(implementation as any); } else { - impl = getDefaultHandler(methodType, name); + impl = getDefaultHandler(methodType, name as string); } const success = this.register( From fba1ee0cc398c63d0a3e960e8418eb8dd3dbe30c Mon Sep 17 00:00:00 2001 From: Slavo Vojacek Date: Wed, 2 Sep 2020 20:32:31 +0100 Subject: [PATCH 068/123] fix(grpc): Fix typings --- packages/grpc-js/src/server.ts | 10 +++++----- packages/grpc-js/test/test-server.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 9b5f3af8..64c17a02 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -146,7 +146,7 @@ export class Server { addService< ImplementationType extends { - readonly [index in keyof ImplementationType]: UntypedHandleCall; + [key: string]: any } >( service: ServiceDefinition, @@ -165,7 +165,7 @@ export class Server { throw new Error('addService() requires two objects as arguments'); } - const serviceKeys = Object.keys(service) as Array; + const serviceKeys = Object.keys(service); if (serviceKeys.length === 0) { throw new Error('Cannot add an empty service to a server'); @@ -193,13 +193,13 @@ export class Server { let impl; if (implFn === undefined && typeof attrs.originalName === 'string') { - implFn = implementation[attrs.originalName as keyof ImplementationType]; + implFn = implementation[attrs.originalName]; } if (implFn !== undefined) { - impl = implFn.bind(implementation as any); + impl = implFn.bind(implementation); } else { - impl = getDefaultHandler(methodType, name as string); + impl = getDefaultHandler(methodType, name); } const success = this.register( diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index f8b13b30..b30963fb 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -181,7 +181,7 @@ describe('Server', () => { const server = new Server(); assert.throws(() => { - server.addService({} as any, dummyImpls); + server.addService(({} as any), dummyImpls); }, /Cannot add an empty service to a server/); }); From 2d4ab786da02a5d8de689c96f33cfecad34ccef6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 2 Sep 2020 15:00:46 -0700 Subject: [PATCH 069/123] Add xds kokoro config and update the test script --- packages/grpc-js/scripts/xds.sh | 22 +++++++++++++--------- test/kokoro/linux.cfg | 1 - test/kokoro/xds-interop.cfg | 24 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 test/kokoro/xds-interop.cfg diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index ae169eeb..76f6b214 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -1,10 +1,19 @@ #!/bin/bash +# 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 -cd $(dirname $0) -cd .. +cd $(dirname $0)/.. base=$(pwd) npm run compile @@ -14,14 +23,9 @@ git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git grpc/tools/run_tests/helper_scripts/prep_xds.sh -# Test cases "path_matching" and "header_matching" are not included in "all", -# because not all interop clients in all languages support these new tests. -# -# TODO: remove "path_matching" and "header_matching" from --test_case after -# they are added into "all". -GRPC_NODE_TRACE=all GRPC_NODE_VERBOSITY=DEBUG \ +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 \ python3 grpc/tools/run_tests/run_xds_tests.py \ - --test_case="all" \ + --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 \ diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index 24ed01ab..f40e6db4 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -20,6 +20,5 @@ timeout_mins: 60 action { define_artifacts { regex: "github/grpc-node/reports/**/sponge_log.xml" - regex: "github/grpc/reports/**" } } diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg new file mode 100644 index 00000000..81a03873 --- /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/scripts/xds.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "github/grpc/reports/**" + } +} From 1fc284f59d67b4120dec5f8fc6372f5aa5741eca Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 2 Sep 2020 15:17:57 -0700 Subject: [PATCH 070/123] Revert "fix(grpc-js): Add support for impl type to server.addService" --- packages/grpc-js/src/server.ts | 10 +++------- packages/grpc-js/test/test-server.ts | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 64c17a02..8d8952e8 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -144,13 +144,9 @@ export class Server { throw new Error('Not implemented. Use addService() instead'); } - addService< - ImplementationType extends { - [key: string]: any - } - >( - service: ServiceDefinition, - implementation: ImplementationType + addService( + service: ServiceDefinition, + implementation: UntypedServiceImplementation ): void { if (this.started === true) { throw new Error("Can't add a service to a started server."); diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index b30963fb..434efbbc 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -181,7 +181,7 @@ describe('Server', () => { const server = new Server(); assert.throws(() => { - server.addService(({} as any), dummyImpls); + server.addService({}, dummyImpls); }, /Cannot add an empty service to a server/); }); From d8e00689d05cc0b5e5e46f60628edb30d9279c4b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 3 Sep 2020 14:32:30 -0700 Subject: [PATCH 071/123] Bump grpc-js to 1.1.6 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 7deb248e..a8428b24 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.5", + "version": "1.1.6", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 46ac39b1e2c3314cb73e216b30ff02c21c0f0ff2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 10 Sep 2020 09:56:45 -0700 Subject: [PATCH 072/123] Add copyright notice to the new script --- packages/grpc-js/scripts/xds.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index 76f6b214..bd30702c 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -1,4 +1,17 @@ #!/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. # Install NVM cd ~ From b99872eee7e2a39f8345f01431376f0813885783 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 10 Sep 2020 14:50:18 -0700 Subject: [PATCH 073/123] grpc-js: xDS: handle insecure and google_default bootstrap creds --- packages/grpc-js/src/xds-client.ts | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 0b1fa7b9..8ca4cfa2 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -19,7 +19,7 @@ import * as protoLoader from '@grpc/proto-loader'; import { loadPackageDefinition } from './make-client'; import * as adsTypes from './generated/ads'; import * as lrsTypes from './generated/lrs'; -import { createGoogleDefaultCredentials } from './channel-credentials'; +import { createGoogleDefaultCredentials, ChannelCredentials } from './channel-credentials'; import { loadBootstrapInfo } from './xds-bootstrap'; import { ClientDuplexStream, ServiceError } from './call'; import { StatusObject } from './call-stream'; @@ -805,17 +805,38 @@ export class XdsClient { ...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, - createGoogleDefaultCredentials(), + channelCreds, channelArgs ); this.maybeStartAdsStream(); this.lrsClient = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( bootstrapInfo.xdsServers[0].serverUri, - createGoogleDefaultCredentials(), + channelCreds, {channelOverride: this.adsClient.getChannel()} ); this.maybeStartLrsStream(); From 58801acf1ef14c40c325d6b00b6730d4ca7cfc3e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 11 Sep 2020 10:47:09 -0700 Subject: [PATCH 074/123] grpc-js: Fix path handling in xds interop script --- packages/grpc-js/scripts/xds.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index bd30702c..12666069 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -13,6 +13,9 @@ # 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 @@ -26,8 +29,7 @@ nvm install 12 set -exu -o pipefail [[ -f /VERSION ]] && cat /VERSION -cd $(dirname $0)/.. -base=$(pwd) +cd $base npm run compile cd ../../.. From d32734f49153141b20a1e0e10a3fb3d25a5dcde2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 11 Sep 2020 13:03:31 -0700 Subject: [PATCH 075/123] grpc-js: Allow clients and servers to send metadata of unlimited size --- packages/grpc-js/src/server.ts | 4 +++- packages/grpc-js/src/subchannel.ts | 1 + test/api/interop_extra_test.js | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 8d8952e8..d54d61f4 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -246,7 +246,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'], diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 3be6dd0a..7586d50e 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -291,6 +291,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://'; diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 67130e03..ddd72298 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -168,6 +168,29 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio assert.ifError(error); }); }); + it('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 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; From f6e3ca38114fb4a1987ed4b540925b24164670c0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 11 Sep 2020 13:42:49 -0700 Subject: [PATCH 076/123] Fix an error in the new test --- test/api/interop_extra_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index ddd72298..996fadfd 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -172,7 +172,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio done = multiDone(done, 3); const header = 'X'.repeat(64 * 1024); const trailer = Buffer.from('Y'.repeat(64 * 1024)); - const metadata = new Metadata(); + 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) => { From 876b58ed0c053d7eb11da5bf7d2f855b07a14d65 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 14 Sep 2020 10:30:26 -0700 Subject: [PATCH 077/123] Increase received metadata size limits in the test --- test/api/interop_extra_test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 996fadfd..c7411c17 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() { From 8162efdf54929b427439f41b7da923643b77982e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 14 Sep 2020 15:48:03 -0700 Subject: [PATCH 078/123] grpc-js: Install dependencies in xds script --- packages/grpc-js/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index 12666069..a3f10da3 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -30,7 +30,7 @@ set -exu -o pipefail [[ -f /VERSION ]] && cat /VERSION cd $base -npm run compile +npm install cd ../../.. From 4d44dc11e2a9f5a2cd2dbd7eee9767e50cdd2aec Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 15 Sep 2020 10:41:52 -0700 Subject: [PATCH 079/123] grpc-js: Double the xds test job timeout --- test/kokoro/xds-interop.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg index 81a03873..7aae7d96 100644 --- a/test/kokoro/xds-interop.cfg +++ b/test/kokoro/xds-interop.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/packages/grpc-js/scripts/xds.sh" -timeout_mins: 60 +timeout_mins: 120 action { define_artifacts { regex: "github/grpc/reports/**" From c0f31a8a028009a62089b86728f775ea9fdcf890 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 15 Sep 2020 14:52:00 -0700 Subject: [PATCH 080/123] grpc-js: Source nvm.sh in profile files in xds script to get nvm in subprocesses --- packages/grpc-js/scripts/xds.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index a3f10da3..1c815fda 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -29,6 +29,11 @@ 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 npm install From 2791dbbb2399af32080f942b38411c182473ab2b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 17 Sep 2020 11:25:56 -0700 Subject: [PATCH 081/123] grpc-js: Add a timer that holds the event loop open while there are pending calls --- packages/grpc-js/src/channel.ts | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 3195ebc2..5edaf370 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -137,6 +137,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, @@ -206,6 +214,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); @@ -230,6 +239,14 @@ export class ChannelImplementation implements Channel { new MaxMessageSizeFilterFactory(this.options), new CompressionFilterFactory(this), ]); + + this.callRefTimer = setInterval(() => {}, 1 << 31 - 1); + this.callRefTimer.unref?.(); + } + + private pushPick(callStream: Http2CallStream, callMetadata: Metadata) { + this.callRefTimer.ref?.(); + this.pickQueue.push({ callStream, callMetadata }); } /** @@ -276,7 +293,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 @@ -367,11 +384,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, @@ -433,6 +450,7 @@ export class ChannelImplementation implements Channel { close() { this.resolvingLoadBalancer.destroy(); this.updateState(ConnectivityState.SHUTDOWN); + clearInterval(this.callRefTimer); this.subchannelPool.unrefUnusedSubchannels(); } From 6a32c00ed2cce4179bef5a6df100b879e1f82cca Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 17 Sep 2020 12:15:47 -0700 Subject: [PATCH 082/123] Bump grpc-js to 1.1.7 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index a8428b24..ec3f4a97 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.6", + "version": "1.1.7", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From a1600812d19cf96e501356cf6e97bd237577a204 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 17 Sep 2020 13:18:11 -0700 Subject: [PATCH 083/123] Move timer initialization to the beginning of channel construction --- packages/grpc-js/src/channel.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 5edaf370..dcfae483 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -48,6 +48,11 @@ export enum ConnectivityState { SHUTDOWN, } +/** + * See https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args + */ +const MAX_TIMEOUT_TIME = 2147483647; + let nextCallNumber = 0; function getNewCallNumber(): number { @@ -185,6 +190,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 { @@ -239,9 +248,6 @@ export class ChannelImplementation implements Channel { new MaxMessageSizeFilterFactory(this.options), new CompressionFilterFactory(this), ]); - - this.callRefTimer = setInterval(() => {}, 1 << 31 - 1); - this.callRefTimer.unref?.(); } private pushPick(callStream: Http2CallStream, callMetadata: Metadata) { From a45d8da2046f686e2a4b8d7aedd3df2525d3495a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 21 Sep 2020 11:12:38 -0700 Subject: [PATCH 084/123] Add debugging output to xds scripts --- packages/grpc-js/interop/xds-interop-client.ts | 3 +++ packages/grpc-js/scripts/xds.sh | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index 3009541c..daaf4761 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -15,6 +15,9 @@ * */ +console.log(`Running xDS interop client on node ${process.version} from ${process.argv[0]}`); +console.log(`PATH: ${process.env.PATH}`); + import * as grpc from '../src'; import { ProtoGrpcType } from './generated/test'; diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index 1c815fda..f6c18770 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -34,6 +34,10 @@ echo "source $NVM_DIR/nvm.sh" > ~/.profile echo "source $NVM_DIR/nvm.sh" > ~/.shrc export ENV=~/.shrc +echo $PATH +which node +node -v + cd $base npm install @@ -43,7 +47,9 @@ 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 \ +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 \ From 6e0f6e2f8a41ab30c78822d389634d3cac20369d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 21 Sep 2020 11:13:19 -0700 Subject: [PATCH 085/123] Borrow linux kokoro job for xds tests (revert before merging) --- test/kokoro/linux.cfg | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index f40e6db4..04fa7333 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,10 +15,11 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/test/kokoro.sh" -timeout_mins: 60 +build_file: "grpc-node/packages/grpc-js/scripts/xds.sh" +timeout_mins: 120 action { define_artifacts { - regex: "github/grpc-node/reports/**/sponge_log.xml" + regex: "github/grpc/reports/**" } } + From c259edd7f89a2c01b6e09c6dd6d3e3b9fb375346 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 21 Sep 2020 13:33:37 -0700 Subject: [PATCH 086/123] Patch xds python script with debug logging --- 0001-Add-PATH-logging.patch | 32 ++++++++++++++++++++++++++++++++ packages/grpc-js/scripts/xds.sh | 4 ++++ 2 files changed, 36 insertions(+) create mode 100644 0001-Add-PATH-logging.patch diff --git a/0001-Add-PATH-logging.patch b/0001-Add-PATH-logging.patch new file mode 100644 index 00000000..29c410a2 --- /dev/null +++ b/0001-Add-PATH-logging.patch @@ -0,0 +1,32 @@ +From 0761cc8780a5f94c10f187dbcd8d8e70c7b52577 Mon Sep 17 00:00:00 2001 +From: Michael Lumish +Date: Mon, 21 Sep 2020 13:28:08 -0700 +Subject: [PATCH] Add PATH logging + +--- + tools/run_tests/run_xds_tests.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/run_tests/run_xds_tests.py b/tools/run_tests/run_xds_tests.py +index 0cfa59e..df5a3f9 100755 +--- a/tools/run_tests/run_xds_tests.py ++++ b/tools/run_tests/run_xds_tests.py +@@ -1730,6 +1730,7 @@ try: + wait_for_healthy_backends(gcp, backend_service, instance_group) + + if args.test_case: ++ logger.debug('PATH: %s', os.environ['PATH']) + client_env = dict(os.environ) + bootstrap_server_features = [] + if gcp.service_port == _DEFAULT_SERVICE_PORT: +@@ -1800,6 +1801,7 @@ try: + rpcs_to_send=rpcs_to_send, + metadata_to_send=metadata_to_send) + logger.debug('running client: %s', client_cmd_formatted) ++ logger.debug('Using PATH: %s', client_env['PATH']) + client_cmd = shlex.split(client_cmd_formatted) + try: + client_process = subprocess.Popen(client_cmd, +-- +2.7.4 + diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index f6c18770..ad4744ec 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -45,6 +45,10 @@ cd ../../.. git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git +cd grpc +git apply ../grpc-node/0001-Add-PATH-logging.patch +cd .. + 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 From 2574952e06cc57fa033eefe1be1e868861e309b2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 21 Sep 2020 14:15:21 -0700 Subject: [PATCH 087/123] Use full node path in client_cmd --- packages/grpc-js/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index ad4744ec..ae2362d6 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -61,7 +61,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh --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="node grpc-node/packages/grpc-js/build/interop/xds-interop-client \ + --client_cmd="$(which node) grpc-node/packages/grpc-js/build/interop/xds-interop-client \ --server=xds:///{server_uri} \ --stats_port={stats_port} \ --qps={qps} \ From ab5878e737f85d852aece8b92200e99929a43b8c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 21 Sep 2020 16:32:46 -0700 Subject: [PATCH 088/123] Increase timeout for borrowed test --- test/kokoro/linux.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index 04fa7333..e23febc6 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/packages/grpc-js/scripts/xds.sh" -timeout_mins: 120 +timeout_mins: 360 action { define_artifacts { regex: "github/grpc/reports/**" From 474a496a7a9695f3ad8fd4a9cc6e106bcb2e7be9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 22 Sep 2020 00:47:55 -0700 Subject: [PATCH 089/123] Update submodules in xds test script --- packages/grpc-js/scripts/xds.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index ae2362d6..c15db9fc 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -39,6 +39,7 @@ which node node -v cd $base +git submodule update --init --recursive npm install cd ../../.. From fbdfcd4ee963ec3cb5a5aeea835c36278f119622 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 22 Sep 2020 10:56:11 -0700 Subject: [PATCH 090/123] Fix tracer setting lines in xds script --- packages/grpc-js/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index c15db9fc..ea472bc1 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -52,7 +52,7 @@ cd .. 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_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 \ From 0713b28da51de27311fbd204afff0c02d50d9b16 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 22 Sep 2020 12:09:13 -0700 Subject: [PATCH 091/123] Revert testing changes --- 0001-Add-PATH-logging.patch | 32 ------------------- .../grpc-js/interop/xds-interop-client.ts | 3 -- packages/grpc-js/scripts/xds.sh | 8 ----- test/kokoro/linux.cfg | 7 ++-- 4 files changed, 3 insertions(+), 47 deletions(-) delete mode 100644 0001-Add-PATH-logging.patch diff --git a/0001-Add-PATH-logging.patch b/0001-Add-PATH-logging.patch deleted file mode 100644 index 29c410a2..00000000 --- a/0001-Add-PATH-logging.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0761cc8780a5f94c10f187dbcd8d8e70c7b52577 Mon Sep 17 00:00:00 2001 -From: Michael Lumish -Date: Mon, 21 Sep 2020 13:28:08 -0700 -Subject: [PATCH] Add PATH logging - ---- - tools/run_tests/run_xds_tests.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/tools/run_tests/run_xds_tests.py b/tools/run_tests/run_xds_tests.py -index 0cfa59e..df5a3f9 100755 ---- a/tools/run_tests/run_xds_tests.py -+++ b/tools/run_tests/run_xds_tests.py -@@ -1730,6 +1730,7 @@ try: - wait_for_healthy_backends(gcp, backend_service, instance_group) - - if args.test_case: -+ logger.debug('PATH: %s', os.environ['PATH']) - client_env = dict(os.environ) - bootstrap_server_features = [] - if gcp.service_port == _DEFAULT_SERVICE_PORT: -@@ -1800,6 +1801,7 @@ try: - rpcs_to_send=rpcs_to_send, - metadata_to_send=metadata_to_send) - logger.debug('running client: %s', client_cmd_formatted) -+ logger.debug('Using PATH: %s', client_env['PATH']) - client_cmd = shlex.split(client_cmd_formatted) - try: - client_process = subprocess.Popen(client_cmd, --- -2.7.4 - diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index daaf4761..3009541c 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -15,9 +15,6 @@ * */ -console.log(`Running xDS interop client on node ${process.version} from ${process.argv[0]}`); -console.log(`PATH: ${process.env.PATH}`); - import * as grpc from '../src'; import { ProtoGrpcType } from './generated/test'; diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index ea472bc1..ce2b6417 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -34,10 +34,6 @@ echo "source $NVM_DIR/nvm.sh" > ~/.profile echo "source $NVM_DIR/nvm.sh" > ~/.shrc export ENV=~/.shrc -echo $PATH -which node -node -v - cd $base git submodule update --init --recursive npm install @@ -46,10 +42,6 @@ cd ../../.. git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git -cd grpc -git apply ../grpc-node/0001-Add-PATH-logging.patch -cd .. - 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 \ diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index e23febc6..f40e6db4 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,11 +15,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/packages/grpc-js/scripts/xds.sh" -timeout_mins: 360 +build_file: "grpc-node/test/kokoro.sh" +timeout_mins: 60 action { define_artifacts { - regex: "github/grpc/reports/**" + regex: "github/grpc-node/reports/**/sponge_log.xml" } } - From 980e30c671144181ecf948e80641d043763d9c60 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 22 Sep 2020 16:05:43 -0700 Subject: [PATCH 092/123] Fix the max message size tests by making the requests with different clients --- test/api/interop_extra_test.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 67130e03..934f3514 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -257,6 +257,7 @@ 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; before(function(done) { interopServer.getServer(0, true, (err, serverObj) => { if (err) { @@ -273,6 +274,7 @@ 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}); done(); } }, {'grpc.max_send_message_length': 4 * 1024 * 1024}); @@ -284,7 +286,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 +299,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) => { 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 = restrictedServerClient2.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) => { + }); }); }); }); From 1a5f25de619d444e1963d938133ca8a5d613c654 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 23 Sep 2020 11:56:41 -0700 Subject: [PATCH 093/123] Use 4 clients for 4 requests, to avoid weird core client behavior --- test/api/interop_extra_test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 934f3514..99f91e21 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -258,6 +258,8 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio let restrictedServer; let restrictedServerClient; let restrictedServerClient2; + let restrictedServerClient3; + let restrictedServerClient4; before(function(done) { interopServer.getServer(0, true, (err, serverObj) => { if (err) { @@ -275,6 +277,8 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }; 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}); @@ -299,10 +303,10 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); }); it('should get an error when requesting a large message', function(done) { - restrictedServerClient.unaryCall({response_size: largeMessageSize}, (error, result) => { + restrictedServerClient3.unaryCall({response_size: largeMessageSize}, (error, result) => { assert(error); assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); - const stream = restrictedServerClient2.fullDuplexCall(); + const stream = restrictedServerClient4.fullDuplexCall(); stream.write({response_parameters: [{size: largeMessageSize}]}); stream.end(); stream.on('data', () => {}); From f3d14bd2b39bd50c88cc3f123ed6fec8edeb8d46 Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Thu, 24 Sep 2020 08:19:33 +0100 Subject: [PATCH 094/123] grpc-js: export handleClientStreamingCall type --- packages/grpc-js/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index f79a369b..89e604e3 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 = From dcf47460da01f50a752facbf092949f2031bd3f6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 24 Sep 2020 14:01:15 -0700 Subject: [PATCH 095/123] grpc-js: xDS: Do not remove watchers in onResourceDoesNotExist --- packages/grpc-js/src/load-balancer-cds.ts | 4 ---- packages/grpc-js/src/load-balancer-eds.ts | 4 ---- 2 files changed, 8 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-cds.ts b/packages/grpc-js/src/load-balancer-cds.ts index 01cc4c62..71a72c89 100644 --- a/packages/grpc-js/src/load-balancer-cds.ts +++ b/packages/grpc-js/src/load-balancer-cds.ts @@ -86,10 +86,6 @@ export class CdsLoadBalancer implements LoadBalancer { ); }, onResourceDoesNotExist: () => { - this.xdsClient?.removeClusterWatcher( - this.latestConfig!.cds.cluster, - this.watcher - ); 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(); diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index ccc56e9f..902b28b5 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -140,10 +140,6 @@ export class EdsLoadBalancer implements LoadBalancer { this.updateChild(); }, onResourceDoesNotExist: () => { - this.xdsClient?.removeEndpointWatcher( - this.edsServiceName!, - this.watcher - ); 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(); From 73d3c307c934b743f44fbd43d32737733f7db8b1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 5 Oct 2020 11:27:18 -0700 Subject: [PATCH 096/123] grpc-js: xds: Add more logging around adding and removing eds and cds watchers --- packages/grpc-js/src/load-balancer-cds.ts | 7 +++++-- packages/grpc-js/src/load-balancer-eds.ts | 5 ++++- packages/grpc-js/src/xds-client.ts | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-cds.ts b/packages/grpc-js/src/load-balancer-cds.ts index 71a72c89..15c55ed8 100644 --- a/packages/grpc-js/src/load-balancer-cds.ts +++ b/packages/grpc-js/src/load-balancer-cds.ts @@ -111,14 +111,14 @@ export class CdsLoadBalancer implements LoadBalancer { attributes: { [key: string]: unknown } ): void { if (!isCdsLoadBalancingConfig(lbConfig)) { - trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); + 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)); + trace('Received update with config ' + JSON.stringify(lbConfig, undefined, 2)); this.xdsClient = attributes.xdsClient; this.latestAttributes = attributes; @@ -128,6 +128,7 @@ export class CdsLoadBalancer implements LoadBalancer { this.isWatcherActive && this.latestConfig?.cds.cluster !== lbConfig.cds.cluster ) { + trace('Removing old cluster watcher for cluster name ' + this.latestConfig!.cds.cluster); this.xdsClient.removeClusterWatcher( this.latestConfig!.cds.cluster, this.watcher @@ -143,6 +144,7 @@ export class CdsLoadBalancer implements LoadBalancer { this.latestConfig = lbConfig; if (!this.isWatcherActive) { + trace('Adding new cluster watcher for cluster name ' + lbConfig.cds.cluster); this.xdsClient.addClusterWatcher(lbConfig.cds.cluster, this.watcher); this.isWatcherActive = true; } @@ -154,6 +156,7 @@ export class CdsLoadBalancer implements LoadBalancer { this.childBalancer.resetBackoff(); } destroy(): void { + trace('Destroying load balancer with cluster name ' + this.latestConfig?.cds.cluster); this.childBalancer.destroy(); if (this.isWatcherActive) { this.xdsClient?.removeClusterWatcher( diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 902b28b5..9080a2f4 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -401,7 +401,7 @@ export class EdsLoadBalancer implements LoadBalancer { trace('Discarding address list update missing xdsClient attribute'); return; } - trace('Received update with config: ' + JSON.stringify(lbConfig)); + trace('Received update with config: ' + JSON.stringify(lbConfig, undefined, 2)); this.lastestConfig = lbConfig; this.latestAttributes = attributes; this.xdsClient = attributes.xdsClient; @@ -411,6 +411,7 @@ export class EdsLoadBalancer implements LoadBalancer { /* 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 */ @@ -423,6 +424,7 @@ export class EdsLoadBalancer implements LoadBalancer { 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; } @@ -447,6 +449,7 @@ export class EdsLoadBalancer implements LoadBalancer { this.childBalancer.resetBackoff(); } destroy(): void { + trace('Destroying load balancer with edsServiceName ' + this.edsServiceName); if (this.edsServiceName) { this.xdsClient?.removeEndpointWatcher(this.edsServiceName, this.watcher); } diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 8ca4cfa2..8b4d5d3b 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -261,7 +261,6 @@ class EdsState implements XdsStreamState { edsServiceName: string, watcher: Watcher ): void { - trace('Adding EDS watcher for edsServiceName ' + edsServiceName); let watchersEntry = this.watchers.get(edsServiceName); let addedServiceName = false; if (watchersEntry === undefined) { @@ -269,6 +268,7 @@ class EdsState implements XdsStreamState { 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, @@ -298,6 +298,7 @@ class EdsState implements XdsStreamState { 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) { From 89a030c00a3d4f26ebafe9db4ceff1a064f64cd0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 5 Oct 2020 14:58:55 -0700 Subject: [PATCH 097/123] tests: Update google-auth-library dependency from 0.9 to 6.1 --- test/interop/interop_client.js | 64 ++++++++++------------------------ test/package.json | 2 +- 2 files changed, 19 insertions(+), 47 deletions(-) diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 1c2ec8f3..0b177e53 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,31 @@ function oauth2Test(client, done, extra) { } function perRpcAuthTest(client, done, extra) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { + 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/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" From bbd7617ba746579a98792df5951b4a8237a62b8d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 12 Oct 2020 10:23:03 -0700 Subject: [PATCH 098/123] Move grpc-js xDS features into a separate package --- packages/grpc-js-xds/.eslintrc.json | 3 +++ packages/grpc-js-xds/.prettierrc.js | 3 +++ packages/grpc-js-xds/package.json | 41 +++++++++++++++++++++++++++++ packages/grpc-js-xds/src/index.ts | 24 +++++++++++++++++ packages/grpc-js-xds/tsconfig.json | 11 ++++++++ packages/grpc-js/package.json | 2 -- 6 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 packages/grpc-js-xds/.eslintrc.json create mode 100644 packages/grpc-js-xds/.prettierrc.js create mode 100644 packages/grpc-js-xds/package.json create mode 100644 packages/grpc-js-xds/src/index.ts create mode 100644 packages/grpc-js-xds/tsconfig.json 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/package.json b/packages/grpc-js-xds/package.json new file mode 100644 index 00000000..f8d44cb0 --- /dev/null +++ b/packages/grpc-js-xds/package.json @@ -0,0 +1,41 @@ +{ + "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" + }, + "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": { + "gts": "^2.0.2", + "typescript": "^3.8.3", + "@types/node": "^13.11.1", + "yargs": "^15.4.1" + }, + "dependencies": { + "@grpc/proto-loader": "^0.6.0-pre14", + "google-auth-library": "^6.1.1" + } +} diff --git a/packages/grpc-js-xds/src/index.ts b/packages/grpc-js-xds/src/index.ts new file mode 100644 index 00000000..2c1da126 --- /dev/null +++ b/packages/grpc-js-xds/src/index.ts @@ -0,0 +1,24 @@ +console.log('Try npm run check/fix!'); + +const longString = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut aliquet diam.'; + +const trailing = 'Semicolon'; + +const why = 'am I tabbed?'; + +export function doSomeStuff( + withThis: string, + andThat: string, + andThose: string[] +) { + //function on one line + if (!andThose.length) { + return false; + } + console.log(withThis); + console.log(andThat); + console.dir(andThose); + return; +} +// TODO: more examples diff --git a/packages/grpc-js-xds/tsconfig.json b/packages/grpc-js-xds/tsconfig.json new file mode 100644 index 00000000..d1646f01 --- /dev/null +++ b/packages/grpc-js-xds/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "./node_modules/gts/tsconfig-google.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ] +} diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index b2804381..45c4cad4 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -58,9 +58,7 @@ "posttest": "npm run check" }, "dependencies": { - "@grpc/proto-loader": "^0.6.0-pre14", "@types/node": "^12.12.47", - "google-auth-library": "^5.10.1", "semver": "^6.2.0" }, "files": [ From 4368ed37b8ae4e1ac1226439b1ca32453f430eec Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 12 Oct 2020 10:40:32 -0700 Subject: [PATCH 099/123] Fix missing arg variable in perRpcCreds interop test --- test/interop/interop_client.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 0b177e53..d7df128d 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -464,6 +464,10 @@ function oauth2Test(client, done, extra) { } function perRpcAuthTest(client, done, extra) { + 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); From 967eeb5443891fba1230438d85d649bc9219b66e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 20 Oct 2020 11:04:11 -0700 Subject: [PATCH 100/123] grpc-js: Prevent prototype pollution in loadPackageDefinition --- packages/grpc-js/src/make-client.ts | 8 +++++- .../grpc-js/test/test-prototype-pollution.ts | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 packages/grpc-js/test/test-prototype-pollution.ts 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/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); + }); +}); From a6a8639343ad79c6548cae0cc331834d7c4f44a5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 20 Oct 2020 10:38:00 -0700 Subject: [PATCH 101/123] grpc-js: Separate xds code into a separate plugin package --- .gitmodules | 16 +- .../{grpc-js => grpc-js-xds}/deps/envoy-api | 0 .../{grpc-js => grpc-js-xds}/deps/googleapis | 0 .../deps/protoc-gen-validate | 0 packages/{grpc-js => grpc-js-xds}/deps/udpa | 0 .../generated/grpc/testing/BoolValue.ts | 0 .../generated/grpc/testing/EchoStatus.ts | 0 .../interop/generated/grpc/testing/Empty.ts | 0 .../generated/grpc/testing/GrpclbRouteType.ts | 0 .../grpc/testing/LoadBalancerStatsRequest.ts | 0 .../grpc/testing/LoadBalancerStatsResponse.ts | 0 .../grpc/testing/LoadBalancerStatsService.ts | 2 +- .../interop/generated/grpc/testing/Payload.ts | 0 .../generated/grpc/testing/PayloadType.ts | 0 .../generated/grpc/testing/ReconnectInfo.ts | 0 .../generated/grpc/testing/ReconnectParams.ts | 0 .../grpc/testing/ReconnectService.ts | 2 +- .../grpc/testing/ResponseParameters.ts | 0 .../generated/grpc/testing/SimpleRequest.ts | 0 .../generated/grpc/testing/SimpleResponse.ts | 0 .../grpc/testing/StreamingInputCallRequest.ts | 0 .../testing/StreamingInputCallResponse.ts | 0 .../testing/StreamingOutputCallRequest.ts | 0 .../testing/StreamingOutputCallResponse.ts | 0 .../generated/grpc/testing/TestService.ts | 2 +- .../grpc/testing/UnimplementedService.ts | 2 +- .../grpc/testing/XdsUpdateHealthService.ts | 2 +- .../interop/generated/test.ts | 2 +- .../interop/xds-interop-client.ts | 6 +- packages/grpc-js-xds/package.json | 9 +- .../proto/grpc/testing/empty.proto | 0 .../proto/grpc/testing/messages.proto | 0 .../proto/grpc/testing/test.proto | 0 .../{grpc-js => grpc-js-xds}/scripts/xds.sh | 4 + .../src/generated/ads.ts | 4 +- .../src/generated/cluster.ts | 4 +- .../src/generated/endpoint.ts | 4 +- .../src/generated/envoy/api/v2/Cluster.ts | 0 .../envoy/api/v2/ClusterLoadAssignment.ts | 0 .../envoy/api/v2/DeltaDiscoveryRequest.ts | 0 .../envoy/api/v2/DeltaDiscoveryResponse.ts | 0 .../envoy/api/v2/DiscoveryRequest.ts | 0 .../envoy/api/v2/DiscoveryResponse.ts | 0 .../src/generated/envoy/api/v2/Listener.ts | 0 .../envoy/api/v2/LoadBalancingPolicy.ts | 0 .../src/generated/envoy/api/v2/Resource.ts | 0 .../envoy/api/v2/RouteConfiguration.ts | 0 .../envoy/api/v2/ScopedRouteConfiguration.ts | 0 .../envoy/api/v2/UpstreamBindConfig.ts | 0 .../envoy/api/v2/UpstreamConnectionOptions.ts | 0 .../src/generated/envoy/api/v2/Vhds.ts | 0 .../v2/auth/CertificateValidationContext.ts | 0 .../envoy/api/v2/auth/CommonTlsContext.ts | 0 .../envoy/api/v2/auth/DownstreamTlsContext.ts | 0 .../envoy/api/v2/auth/GenericSecret.ts | 0 .../envoy/api/v2/auth/PrivateKeyProvider.ts | 0 .../envoy/api/v2/auth/SdsSecretConfig.ts | 0 .../src/generated/envoy/api/v2/auth/Secret.ts | 0 .../envoy/api/v2/auth/TlsCertificate.ts | 0 .../envoy/api/v2/auth/TlsParameters.ts | 0 .../envoy/api/v2/auth/TlsSessionTicketKeys.ts | 0 .../envoy/api/v2/auth/UpstreamTlsContext.ts | 0 .../envoy/api/v2/cluster/CircuitBreakers.ts | 0 .../generated/envoy/api/v2/cluster/Filter.ts | 0 .../envoy/api/v2/cluster/OutlierDetection.ts | 0 .../generated/envoy/api/v2/core/Address.ts | 0 .../api/v2/core/AggregatedConfigSource.ts | 0 .../envoy/api/v2/core/ApiConfigSource.ts | 0 .../generated/envoy/api/v2/core/ApiVersion.ts | 0 .../envoy/api/v2/core/AsyncDataSource.ts | 0 .../envoy/api/v2/core/BackoffStrategy.ts | 0 .../generated/envoy/api/v2/core/BindConfig.ts | 0 .../envoy/api/v2/core/BuildVersion.ts | 0 .../generated/envoy/api/v2/core/CidrRange.ts | 0 .../envoy/api/v2/core/ConfigSource.ts | 0 .../envoy/api/v2/core/ControlPlane.ts | 0 .../generated/envoy/api/v2/core/DataSource.ts | 0 .../envoy/api/v2/core/EventServiceConfig.ts | 0 .../generated/envoy/api/v2/core/Extension.ts | 0 .../envoy/api/v2/core/GrpcProtocolOptions.ts | 0 .../envoy/api/v2/core/GrpcService.ts | 0 .../generated/envoy/api/v2/core/HeaderMap.ts | 0 .../envoy/api/v2/core/HeaderValue.ts | 0 .../envoy/api/v2/core/HeaderValueOption.ts | 0 .../envoy/api/v2/core/HealthCheck.ts | 0 .../envoy/api/v2/core/HealthStatus.ts | 0 .../envoy/api/v2/core/Http1ProtocolOptions.ts | 0 .../envoy/api/v2/core/Http2ProtocolOptions.ts | 0 .../envoy/api/v2/core/HttpProtocolOptions.ts | 0 .../generated/envoy/api/v2/core/HttpUri.ts | 0 .../generated/envoy/api/v2/core/Locality.ts | 0 .../generated/envoy/api/v2/core/Metadata.ts | 0 .../src/generated/envoy/api/v2/core/Node.ts | 0 .../src/generated/envoy/api/v2/core/Pipe.ts | 0 .../envoy/api/v2/core/RateLimitSettings.ts | 0 .../envoy/api/v2/core/RemoteDataSource.ts | 0 .../envoy/api/v2/core/RequestMethod.ts | 0 .../envoy/api/v2/core/RetryPolicy.ts | 0 .../envoy/api/v2/core/RoutingPriority.ts | 0 .../envoy/api/v2/core/RuntimeDouble.ts | 0 .../envoy/api/v2/core/RuntimeFeatureFlag.ts | 0 .../api/v2/core/RuntimeFractionalPercent.ts | 0 .../envoy/api/v2/core/RuntimeUInt32.ts | 0 .../envoy/api/v2/core/SelfConfigSource.ts | 0 .../envoy/api/v2/core/SocketAddress.ts | 0 .../envoy/api/v2/core/SocketOption.ts | 0 .../envoy/api/v2/core/TcpKeepalive.ts | 0 .../envoy/api/v2/core/TcpProtocolOptions.ts | 0 .../envoy/api/v2/core/TrafficDirection.ts | 0 .../envoy/api/v2/core/TransportSocket.ts | 0 .../v2/core/UpstreamHttpProtocolOptions.ts | 0 .../envoy/api/v2/endpoint/ClusterStats.ts | 0 .../envoy/api/v2/endpoint/Endpoint.ts | 0 .../v2/endpoint/EndpointLoadMetricStats.ts | 0 .../envoy/api/v2/endpoint/LbEndpoint.ts | 0 .../api/v2/endpoint/LocalityLbEndpoints.ts | 0 .../api/v2/endpoint/UpstreamEndpointStats.ts | 0 .../api/v2/endpoint/UpstreamLocalityStats.ts | 0 .../v2/listener/ActiveRawUdpListenerConfig.ts | 0 .../generated/envoy/api/v2/listener/Filter.ts | 0 .../envoy/api/v2/listener/FilterChain.ts | 0 .../envoy/api/v2/listener/FilterChainMatch.ts | 0 .../envoy/api/v2/listener/ListenerFilter.ts | 0 .../ListenerFilterChainMatchPredicate.ts | 0 .../api/v2/listener/UdpListenerConfig.ts | 0 .../envoy/api/v2/route/CorsPolicy.ts | 0 .../generated/envoy/api/v2/route/Decorator.ts | 0 .../api/v2/route/DirectResponseAction.ts | 0 .../envoy/api/v2/route/FilterAction.ts | 0 .../envoy/api/v2/route/HeaderMatcher.ts | 0 .../envoy/api/v2/route/HedgePolicy.ts | 0 .../api/v2/route/QueryParameterMatcher.ts | 0 .../generated/envoy/api/v2/route/RateLimit.ts | 0 .../envoy/api/v2/route/RedirectAction.ts | 0 .../envoy/api/v2/route/RetryPolicy.ts | 0 .../src/generated/envoy/api/v2/route/Route.ts | 0 .../envoy/api/v2/route/RouteAction.ts | 0 .../envoy/api/v2/route/RouteMatch.ts | 0 .../generated/envoy/api/v2/route/Tracing.ts | 0 .../envoy/api/v2/route/VirtualCluster.ts | 0 .../envoy/api/v2/route/VirtualHost.ts | 0 .../envoy/api/v2/route/WeightedCluster.ts | 0 .../config/filter/accesslog/v2/AccessLog.ts | 0 .../filter/accesslog/v2/AccessLogFilter.ts | 0 .../config/filter/accesslog/v2/AndFilter.ts | 0 .../filter/accesslog/v2/ComparisonFilter.ts | 0 .../filter/accesslog/v2/DurationFilter.ts | 0 .../filter/accesslog/v2/ExtensionFilter.ts | 0 .../filter/accesslog/v2/GrpcStatusFilter.ts | 0 .../filter/accesslog/v2/HeaderFilter.ts | 0 .../accesslog/v2/NotHealthCheckFilter.ts | 0 .../config/filter/accesslog/v2/OrFilter.ts | 0 .../filter/accesslog/v2/ResponseFlagFilter.ts | 0 .../filter/accesslog/v2/RuntimeFilter.ts | 0 .../filter/accesslog/v2/StatusCodeFilter.ts | 0 .../filter/accesslog/v2/TraceableFilter.ts | 0 .../v2/HttpConnectionManager.ts | 0 .../http_connection_manager/v2/HttpFilter.ts | 0 .../network/http_connection_manager/v2/Rds.ts | 0 .../v2/RequestIDExtension.ts | 0 .../http_connection_manager/v2/ScopedRds.ts | 0 .../v2/ScopedRouteConfigurationsList.ts | 0 .../v2/ScopedRoutes.ts | 0 .../envoy/config/listener/v2/ApiListener.ts | 0 .../envoy/config/trace/v2/Tracing.ts | 0 .../envoy/service/discovery/v2/AdsDummy.ts | 0 .../v2/AggregatedDiscoveryService.ts | 8 +- .../load_stats/v2/LoadReportingService.ts | 6 +- .../service/load_stats/v2/LoadStatsRequest.ts | 0 .../load_stats/v2/LoadStatsResponse.ts | 0 .../generated/envoy/type/CodecClientType.ts | 0 .../src/generated/envoy/type/DoubleRange.ts | 0 .../generated/envoy/type/FractionalPercent.ts | 0 .../src/generated/envoy/type/Int32Range.ts | 0 .../src/generated/envoy/type/Int64Range.ts | 0 .../src/generated/envoy/type/Percent.ts | 0 .../generated/envoy/type/SemanticVersion.ts | 0 .../envoy/type/matcher/ListStringMatcher.ts | 0 .../type/matcher/RegexMatchAndSubstitute.ts | 0 .../envoy/type/matcher/RegexMatcher.ts | 0 .../envoy/type/matcher/StringMatcher.ts | 0 .../envoy/type/metadata/v2/MetadataKey.ts | 0 .../envoy/type/metadata/v2/MetadataKind.ts | 0 .../envoy/type/tracing/v2/CustomTag.ts | 0 .../generated/google/api/CustomHttpPattern.ts | 0 .../src/generated/google/api/Http.ts | 0 .../src/generated/google/api/HttpRule.ts | 0 .../src/generated/google/protobuf/Any.ts | 0 .../generated/google/protobuf/BoolValue.ts | 0 .../generated/google/protobuf/BytesValue.ts | 0 .../google/protobuf/DescriptorProto.ts | 0 .../generated/google/protobuf/DoubleValue.ts | 0 .../src/generated/google/protobuf/Duration.ts | 0 .../src/generated/google/protobuf/Empty.ts | 0 .../google/protobuf/EnumDescriptorProto.ts | 0 .../generated/google/protobuf/EnumOptions.ts | 0 .../protobuf/EnumValueDescriptorProto.ts | 0 .../google/protobuf/EnumValueOptions.ts | 0 .../google/protobuf/FieldDescriptorProto.ts | 0 .../generated/google/protobuf/FieldOptions.ts | 0 .../google/protobuf/FileDescriptorProto.ts | 0 .../google/protobuf/FileDescriptorSet.ts | 0 .../generated/google/protobuf/FileOptions.ts | 0 .../generated/google/protobuf/FloatValue.ts | 0 .../google/protobuf/GeneratedCodeInfo.ts | 0 .../generated/google/protobuf/Int32Value.ts | 0 .../generated/google/protobuf/Int64Value.ts | 0 .../generated/google/protobuf/ListValue.ts | 0 .../google/protobuf/MessageOptions.ts | 0 .../google/protobuf/MethodDescriptorProto.ts | 0 .../google/protobuf/MethodOptions.ts | 0 .../generated/google/protobuf/NullValue.ts | 0 .../google/protobuf/OneofDescriptorProto.ts | 0 .../generated/google/protobuf/OneofOptions.ts | 0 .../google/protobuf/ServiceDescriptorProto.ts | 0 .../google/protobuf/ServiceOptions.ts | 0 .../google/protobuf/SourceCodeInfo.ts | 0 .../generated/google/protobuf/StringValue.ts | 0 .../src/generated/google/protobuf/Struct.ts | 0 .../generated/google/protobuf/Timestamp.ts | 0 .../generated/google/protobuf/UInt32Value.ts | 0 .../generated/google/protobuf/UInt64Value.ts | 0 .../google/protobuf/UninterpretedOption.ts | 0 .../src/generated/google/protobuf/Value.ts | 0 .../src/generated/google/rpc/Status.ts | 0 .../src/generated/http_connection_manager.ts | 4 +- .../src/generated/listener.ts | 4 +- .../src/generated/lrs.ts | 4 +- .../src/generated/route.ts | 4 +- .../annotations/FieldMigrateAnnotation.ts | 0 .../udpa/annotations/FileMigrateAnnotation.ts | 0 .../udpa/annotations/MigrateAnnotation.ts | 0 .../udpa/annotations/PackageVersionStatus.ts | 0 .../udpa/annotations/StatusAnnotation.ts | 0 .../src/generated/validate/AnyRules.ts | 0 .../src/generated/validate/BoolRules.ts | 0 .../src/generated/validate/BytesRules.ts | 0 .../src/generated/validate/DoubleRules.ts | 0 .../src/generated/validate/DurationRules.ts | 0 .../src/generated/validate/EnumRules.ts | 0 .../src/generated/validate/FieldRules.ts | 0 .../src/generated/validate/Fixed32Rules.ts | 0 .../src/generated/validate/Fixed64Rules.ts | 0 .../src/generated/validate/FloatRules.ts | 0 .../src/generated/validate/Int32Rules.ts | 0 .../src/generated/validate/Int64Rules.ts | 0 .../src/generated/validate/KnownRegex.ts | 0 .../src/generated/validate/MapRules.ts | 0 .../src/generated/validate/MessageRules.ts | 0 .../src/generated/validate/RepeatedRules.ts | 0 .../src/generated/validate/SFixed32Rules.ts | 0 .../src/generated/validate/SFixed64Rules.ts | 0 .../src/generated/validate/SInt32Rules.ts | 0 .../src/generated/validate/SInt64Rules.ts | 0 .../src/generated/validate/StringRules.ts | 0 .../src/generated/validate/TimestampRules.ts | 0 .../src/generated/validate/UInt32Rules.ts | 0 .../src/generated/validate/UInt64Rules.ts | 0 packages/grpc-js-xds/src/index.ts | 52 +- .../src/load-balancer-cds.ts | 109 +- .../src/load-balancer-eds.ts | 167 +-- .../src/load-balancer-lrs.ts | 127 ++- .../src/load-balancer-priority.ts | 100 +- .../src/load-balancer-weighted-target.ts | 92 +- .../src/resolver-xds.ts | 19 +- .../src/xds-bootstrap.ts | 0 .../src/xds-client.ts | 28 +- packages/grpc-js-xds/tsconfig.json | 8 +- packages/grpc-js/log.txt | 971 ++++++++++++++++++ packages/grpc-js/package.json | 2 - packages/grpc-js/src/experimental.ts | 13 + packages/grpc-js/src/index.ts | 5 + .../src/load-balancer-child-handler.ts | 6 +- .../grpc-js/src/load-balancer-pick-first.ts | 22 +- .../grpc-js/src/load-balancer-round-robin.ts | 22 +- packages/grpc-js/src/load-balancer.ts | 67 +- packages/grpc-js/src/load-balancing-config.ts | 271 ----- packages/grpc-js/src/resolver.ts | 2 - .../grpc-js/src/resolving-load-balancer.ts | 11 +- packages/grpc-js/src/service-config.ts | 6 +- packages/grpc-js/tsconfig.json | 3 +- test/kokoro/xds-interop.cfg | 2 +- 282 files changed, 1600 insertions(+), 594 deletions(-) rename packages/{grpc-js => grpc-js-xds}/deps/envoy-api (100%) rename packages/{grpc-js => grpc-js-xds}/deps/googleapis (100%) rename packages/{grpc-js => grpc-js-xds}/deps/protoc-gen-validate (100%) rename packages/{grpc-js => grpc-js-xds}/deps/udpa (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/BoolValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/EchoStatus.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/Empty.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/GrpclbRouteType.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/LoadBalancerStatsService.ts (98%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/Payload.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/PayloadType.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/ReconnectInfo.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/ReconnectParams.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/ReconnectService.ts (99%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/ResponseParameters.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/SimpleRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/SimpleResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/StreamingInputCallRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/StreamingInputCallResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/StreamingOutputCallRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/StreamingOutputCallResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/TestService.ts (99%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/UnimplementedService.ts (98%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/XdsUpdateHealthService.ts (98%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/test.ts (98%) rename packages/{grpc-js => grpc-js-xds}/interop/xds-interop-client.ts (95%) rename packages/{grpc-js => grpc-js-xds}/proto/grpc/testing/empty.proto (100%) rename packages/{grpc-js => grpc-js-xds}/proto/grpc/testing/messages.proto (100%) rename packages/{grpc-js => grpc-js-xds}/proto/grpc/testing/test.proto (100%) rename packages/{grpc-js => grpc-js-xds}/scripts/xds.sh (94%) mode change 100755 => 100644 rename packages/{grpc-js => grpc-js-xds}/src/generated/ads.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/cluster.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/endpoint.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/Cluster.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/ClusterLoadAssignment.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/DiscoveryRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/DiscoveryResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/Listener.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/LoadBalancingPolicy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/Resource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/RouteConfiguration.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/UpstreamBindConfig.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/Vhds.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/CommonTlsContext.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/GenericSecret.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/Secret.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/TlsCertificate.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/TlsParameters.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/cluster/Filter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/cluster/OutlierDetection.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Address.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/ApiConfigSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/ApiVersion.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/AsyncDataSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/BackoffStrategy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/BindConfig.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/BuildVersion.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/CidrRange.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/ConfigSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/ControlPlane.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/DataSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/EventServiceConfig.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Extension.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/GrpcService.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HeaderMap.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HeaderValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HeaderValueOption.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HealthCheck.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HealthStatus.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HttpUri.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Locality.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Metadata.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Node.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Pipe.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RateLimitSettings.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RemoteDataSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RequestMethod.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RetryPolicy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RoutingPriority.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RuntimeDouble.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RuntimeUInt32.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/SelfConfigSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/SocketAddress.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/SocketOption.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/TcpKeepalive.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/TrafficDirection.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/TransportSocket.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/ClusterStats.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/Endpoint.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/Filter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/FilterChain.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/FilterChainMatch.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/ListenerFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/CorsPolicy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/Decorator.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/DirectResponseAction.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/FilterAction.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/HeaderMatcher.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/HedgePolicy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/RateLimit.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/RedirectAction.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/RetryPolicy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/Route.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/RouteAction.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/RouteMatch.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/Tracing.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/VirtualCluster.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/VirtualHost.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/WeightedCluster.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/listener/v2/ApiListener.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/trace/v2/Tracing.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/service/discovery/v2/AdsDummy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts (92%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts (96%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/CodecClientType.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/DoubleRange.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/FractionalPercent.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/Int32Range.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/Int64Range.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/Percent.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/SemanticVersion.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/matcher/ListStringMatcher.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/matcher/RegexMatcher.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/matcher/StringMatcher.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/metadata/v2/MetadataKey.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/metadata/v2/MetadataKind.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/tracing/v2/CustomTag.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/api/CustomHttpPattern.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/api/Http.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/api/HttpRule.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Any.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/BoolValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/BytesValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/DescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/DoubleValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Duration.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Empty.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/EnumDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/EnumOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/EnumValueDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/EnumValueOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/FieldDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/FieldOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/FileDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/FileDescriptorSet.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/FileOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/FloatValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/GeneratedCodeInfo.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Int32Value.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Int64Value.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/ListValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/MessageOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/MethodDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/MethodOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/NullValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/OneofDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/OneofOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/ServiceDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/ServiceOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/SourceCodeInfo.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/StringValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Struct.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Timestamp.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/UInt32Value.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/UInt64Value.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/UninterpretedOption.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Value.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/rpc/Status.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/http_connection_manager.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/listener.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/lrs.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/route.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/udpa/annotations/FieldMigrateAnnotation.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/udpa/annotations/FileMigrateAnnotation.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/udpa/annotations/MigrateAnnotation.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/udpa/annotations/PackageVersionStatus.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/udpa/annotations/StatusAnnotation.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/AnyRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/BoolRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/BytesRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/DoubleRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/DurationRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/EnumRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/FieldRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/Fixed32Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/Fixed64Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/FloatRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/Int32Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/Int64Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/KnownRegex.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/MapRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/MessageRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/RepeatedRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/SFixed32Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/SFixed64Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/SInt32Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/SInt64Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/StringRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/TimestampRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/UInt32Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/UInt64Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/load-balancer-cds.ts (60%) rename packages/{grpc-js => grpc-js-xds}/src/load-balancer-eds.ts (73%) rename packages/{grpc-js => grpc-js-xds}/src/load-balancer-lrs.ts (51%) rename packages/{grpc-js => grpc-js-xds}/src/load-balancer-priority.ts (83%) rename packages/{grpc-js => grpc-js-xds}/src/load-balancer-weighted-target.ts (75%) rename packages/{grpc-js => grpc-js-xds}/src/resolver-xds.ts (84%) rename packages/{grpc-js => grpc-js-xds}/src/xds-bootstrap.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/xds-client.ts (98%) create mode 100644 packages/grpc-js/log.txt create mode 100644 packages/grpc-js/src/experimental.ts delete mode 100644 packages/grpc-js/src/load-balancing-config.ts diff --git a/.gitmodules b/.gitmodules index 7989090c..4a5a1e32 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,15 +1,15 @@ [submodule "packages/grpc-tools/deps/protobuf"] path = packages/grpc-tools/deps/protobuf url = https://github.com/protocolbuffers/protobuf -[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/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/interop/generated/grpc/testing/BoolValue.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/BoolValue.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/BoolValue.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/BoolValue.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/EchoStatus.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/EchoStatus.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/EchoStatus.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/EchoStatus.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/Empty.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/Empty.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/Empty.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/Empty.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/GrpclbRouteType.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/GrpclbRouteType.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/GrpclbRouteType.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/GrpclbRouteType.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts similarity index 98% rename from packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts index eece848b..aa4f409f 100644 --- a/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '../../../../src' +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'; diff --git a/packages/grpc-js/interop/generated/grpc/testing/Payload.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/Payload.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/Payload.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/Payload.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/PayloadType.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/PayloadType.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/PayloadType.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/PayloadType.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/ReconnectInfo.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectInfo.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/ReconnectInfo.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectInfo.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/ReconnectParams.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectParams.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/ReconnectParams.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectParams.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts similarity index 99% rename from packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts index 3829506b..21114765 100644 --- a/packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '../../../../src' +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'; diff --git a/packages/grpc-js/interop/generated/grpc/testing/ResponseParameters.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ResponseParameters.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/ResponseParameters.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/ResponseParameters.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/SimpleRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleRequest.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/SimpleRequest.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/SimpleRequest.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/SimpleResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleResponse.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/SimpleResponse.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/SimpleResponse.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallRequest.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallRequest.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallRequest.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallResponse.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallResponse.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallResponse.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallRequest.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallRequest.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallRequest.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallResponse.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallResponse.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallResponse.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/TestService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts similarity index 99% rename from packages/grpc-js/interop/generated/grpc/testing/TestService.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts index b95b7a97..2ccf45fd 100644 --- a/packages/grpc-js/interop/generated/grpc/testing/TestService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '../../../../src' +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'; diff --git a/packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts similarity index 98% rename from packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts index afbf9117..121dfa91 100644 --- a/packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '../../../../src' +import * as grpc from '@grpc/grpc-js' import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; /** diff --git a/packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts similarity index 98% rename from packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts index f27a461e..f898a16d 100644 --- a/packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '../../../../src' +import * as grpc from '@grpc/grpc-js' import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; /** diff --git a/packages/grpc-js/interop/generated/test.ts b/packages/grpc-js-xds/interop/generated/test.ts similarity index 98% rename from packages/grpc-js/interop/generated/test.ts rename to packages/grpc-js-xds/interop/generated/test.ts index a5c95d95..330dbc9f 100644 --- a/packages/grpc-js/interop/generated/test.ts +++ b/packages/grpc-js-xds/interop/generated/test.ts @@ -1,4 +1,4 @@ -import * as grpc from '../../src'; +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'; diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts similarity index 95% rename from packages/grpc-js/interop/xds-interop-client.ts rename to packages/grpc-js-xds/interop/xds-interop-client.ts index 3009541c..526c5194 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -15,7 +15,9 @@ * */ -import * as grpc from '../src'; +import * as grpc from '@grpc/grpc-js'; + +import * as grpc_xds from '../src'; import { ProtoGrpcType } from './generated/test'; @@ -25,6 +27,8 @@ import { LoadBalancerStatsResponse } from './generated/grpc/testing/LoadBalancer 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, diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index f8d44cb0..af6182c5 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -11,7 +11,9 @@ "fix": "gts fix", "prepare": "npm run compile", "pretest": "npm run compile", - "posttest": "npm run check" + "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", @@ -31,10 +33,15 @@ "devDependencies": { "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/grpc-js": "file:../grpc-js", "@grpc/proto-loader": "^0.6.0-pre14", "google-auth-library": "^6.1.1" } diff --git a/packages/grpc-js/proto/grpc/testing/empty.proto b/packages/grpc-js-xds/proto/grpc/testing/empty.proto similarity index 100% rename from packages/grpc-js/proto/grpc/testing/empty.proto rename to packages/grpc-js-xds/proto/grpc/testing/empty.proto diff --git a/packages/grpc-js/proto/grpc/testing/messages.proto b/packages/grpc-js-xds/proto/grpc/testing/messages.proto similarity index 100% rename from packages/grpc-js/proto/grpc/testing/messages.proto rename to packages/grpc-js-xds/proto/grpc/testing/messages.proto diff --git a/packages/grpc-js/proto/grpc/testing/test.proto b/packages/grpc-js-xds/proto/grpc/testing/test.proto similarity index 100% rename from packages/grpc-js/proto/grpc/testing/test.proto rename to packages/grpc-js-xds/proto/grpc/testing/test.proto diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh old mode 100755 new mode 100644 similarity index 94% rename from packages/grpc-js/scripts/xds.sh rename to packages/grpc-js-xds/scripts/xds.sh index ce2b6417..79c3a17a --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -34,6 +34,10 @@ 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 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/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts 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/src/generated/envoy/api/v2/endpoint/ClusterStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/ClusterStats.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts 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/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts 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/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts 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/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 similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts diff --git a/packages/grpc-js/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 similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts diff --git a/packages/grpc-js/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 similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts diff --git a/packages/grpc-js/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 similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts diff --git a/packages/grpc-js/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 similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts diff --git a/packages/grpc-js/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 similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts diff --git a/packages/grpc-js/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 similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts 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/src/generated/envoy/config/trace/v2/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/trace/v2/Tracing.ts rename to packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts 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/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts similarity index 96% rename from packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts rename to packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts index 13d00694..7db2bad1 100644 --- a/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto -import * as grpc from '../../../../../index' +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'; @@ -72,7 +72,7 @@ export interface LoadReportingServiceClient extends grpc.Client { } -export interface LoadReportingServiceHandlers { +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: @@ -103,6 +103,6 @@ export interface LoadReportingServiceHandlers { * 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, _envoy_service_load_stats_v2_LoadStatsResponse__Output>): void; + StreamLoadStats(call: grpc.ServerDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest__Output, _envoy_service_load_stats_v2_LoadStatsResponse>): void; } diff --git a/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts rename to packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts diff --git a/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts rename to packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts 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 100% rename from packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts 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/src/generated/http_connection_manager.ts b/packages/grpc-js-xds/src/generated/http_connection_manager.ts similarity index 99% rename from packages/grpc-js/src/generated/http_connection_manager.ts rename to packages/grpc-js-xds/src/generated/http_connection_manager.ts index 37fe303b..5a90451a 100644 --- a/packages/grpc-js/src/generated/http_connection_manager.ts +++ b/packages/grpc-js-xds/src/generated/http_connection_manager.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/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/src/generated/lrs.ts b/packages/grpc-js-xds/src/generated/lrs.ts similarity index 99% rename from packages/grpc-js/src/generated/lrs.ts rename to packages/grpc-js-xds/src/generated/lrs.ts index 47c5de6d..56ada2f3 100644 --- a/packages/grpc-js/src/generated/lrs.ts +++ b/packages/grpc-js-xds/src/generated/lrs.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 { LoadReportingServiceClient as _envoy_service_load_stats_v2_LoadReportingServiceClient } from './envoy/service/load_stats/v2/LoadReportingService'; @@ -6,7 +6,7 @@ import { LoadReportingServiceClient as _envoy_service_load_stats_v2_LoadReportin 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/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 index 2c1da126..5aea005d 100644 --- a/packages/grpc-js-xds/src/index.ts +++ b/packages/grpc-js-xds/src/index.ts @@ -1,24 +1,32 @@ -console.log('Try npm run check/fix!'); +/* + * 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. + * + */ -const longString = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut aliquet diam.'; +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'; -const trailing = 'Semicolon'; - -const why = 'am I tabbed?'; - -export function doSomeStuff( - withThis: string, - andThat: string, - andThose: string[] -) { - //function on one line - if (!andThose.length) { - return false; - } - console.log(withThis); - console.log(andThat); - console.dir(andThose); - return; -} -// TODO: more examples +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/src/load-balancer-cds.ts b/packages/grpc-js-xds/src/load-balancer-cds.ts similarity index 60% rename from packages/grpc-js/src/load-balancer-cds.ts rename to packages/grpc-js-xds/src/load-balancer-cds.ts index 15c55ed8..a2961927 100644 --- a/packages/grpc-js/src/load-balancer-cds.ts +++ b/packages/grpc-js-xds/src/load-balancer-cds.ts @@ -15,36 +15,54 @@ * */ -import { - LoadBalancer, - ChannelControlHelper, - registerLoadBalancerType, -} from './load-balancer'; -import { SubchannelAddress } from './subchannel'; -import { - LoadBalancingConfig, - isCdsLoadBalancingConfig, - EdsLbConfig, - CdsLoadBalancingConfig, -} from './load-balancing-config'; +import { connectivityState, status, Metadata, logVerbosity, experimental } from '@grpc/grpc-js'; 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'; -import * as logging from './logging'; -import { LogVerbosity } from './constants'; +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 { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); + 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; @@ -62,41 +80,30 @@ export class CdsLoadBalancer implements LoadBalancer { 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 = ''; - } + /* 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( [], - { name: 'eds', eds: edsConfig }, + 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.channelControlHelper.updateState(connectivityState.TRANSIENT_FAILURE, new UnavailablePicker({code: status.UNAVAILABLE, details: 'CDS resource does not exist', metadata: new Metadata()})); this.childBalancer.destroy(); }, - onTransientError: (status) => { + onTransientError: (statusObj) => { if (this.latestCdsUpdate === null) { channelControlHelper.updateState( - ConnectivityState.TRANSIENT_FAILURE, + connectivityState.TRANSIENT_FAILURE, new UnavailablePicker({ - code: Status.UNAVAILABLE, - details: `xDS request failed with error ${status.details}`, + code: status.UNAVAILABLE, + details: `xDS request failed with error ${statusObj.details}`, metadata: new Metadata(), }) ); @@ -110,7 +117,7 @@ export class CdsLoadBalancer implements LoadBalancer { lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown } ): void { - if (!isCdsLoadBalancingConfig(lbConfig)) { + if (!(lbConfig instanceof CdsLoadBalancingConfig)) { trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig, undefined, 2)); return; } @@ -126,11 +133,11 @@ export class CdsLoadBalancer implements LoadBalancer { * one */ if ( this.isWatcherActive && - this.latestConfig?.cds.cluster !== lbConfig.cds.cluster + this.latestConfig?.getCluster() !== lbConfig.getCluster() ) { - trace('Removing old cluster watcher for cluster name ' + this.latestConfig!.cds.cluster); + trace('Removing old cluster watcher for cluster name ' + this.latestConfig!.getCluster()); this.xdsClient.removeClusterWatcher( - this.latestConfig!.cds.cluster, + this.latestConfig!.getCluster(), this.watcher ); /* Setting isWatcherActive to false here lets us have one code path for @@ -144,8 +151,8 @@ export class CdsLoadBalancer implements LoadBalancer { this.latestConfig = lbConfig; if (!this.isWatcherActive) { - trace('Adding new cluster watcher for cluster name ' + lbConfig.cds.cluster); - this.xdsClient.addClusterWatcher(lbConfig.cds.cluster, this.watcher); + trace('Adding new cluster watcher for cluster name ' + lbConfig.getCluster()); + this.xdsClient.addClusterWatcher(lbConfig.getCluster(), this.watcher); this.isWatcherActive = true; } } @@ -156,11 +163,11 @@ export class CdsLoadBalancer implements LoadBalancer { this.childBalancer.resetBackoff(); } destroy(): void { - trace('Destroying load balancer with cluster name ' + this.latestConfig?.cds.cluster); + trace('Destroying load balancer with cluster name ' + this.latestConfig?.getCluster()); this.childBalancer.destroy(); if (this.isWatcherActive) { this.xdsClient?.removeClusterWatcher( - this.latestConfig!.cds.cluster, + this.latestConfig!.getCluster(), this.watcher ); } @@ -171,5 +178,5 @@ export class CdsLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, CdsLoadBalancer); + registerLoadBalancerType(TYPE_NAME, CdsLoadBalancer, CdsLoadBalancingConfig); } diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts similarity index 73% rename from packages/grpc-js/src/load-balancer-eds.ts rename to packages/grpc-js-xds/src/load-balancer-eds.ts index 9080a2f4..8919f317 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -15,38 +15,29 @@ * */ -import { - LoadBalancer, - ChannelControlHelper, - registerLoadBalancerType, - getFirstUsableConfig, -} from './load-balancer'; -import { SubchannelAddress, subchannelAddressToString } from './subchannel'; -import { - LoadBalancingConfig, - isEdsLoadBalancingConfig, - EdsLoadBalancingConfig, - PriorityLbConfig, - PriorityChild, - WeightedTarget, - PriorityLoadBalancingConfig, -} from './load-balancing-config'; -import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +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 { ConnectivityState } from './channel'; -import { UnavailablePicker, Picker, PickResultType } 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'; -import * as logging from './logging'; -import { LogVerbosity } from './constants'; +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 { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); + experimental.trace(LogVerbosity.DEBUG, TRACER_NAME, text); } const TYPE_NAME = 'eds'; @@ -55,6 +46,71 @@ 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 @@ -317,24 +373,12 @@ export class EdsLoadBalancer implements LoadBalancer { /* Use the endpoint picking policy from the config, default to * round_robin. */ const endpointPickingPolicy: LoadBalancingConfig[] = [ - ...this.lastestConfig.eds.endpointPickingPolicy, - { name: 'round_robin', round_robin: {} }, + ...this.lastestConfig.getEndpointPickingPolicy(), + validateLoadBalancingConfig({ round_robin: {} }), ]; let childPolicy: LoadBalancingConfig[]; - if (this.lastestConfig.eds.lrsLoadReportingServerName) { - childPolicy = [ - { - name: 'lrs', - lrs: { - cluster_name: this.lastestConfig.eds.cluster, - eds_service_name: this.lastestConfig.eds.edsServiceName ?? '', - lrs_load_reporting_server_name: this.lastestConfig.eds - .lrsLoadReportingServerName, - locality: localityObj.locality, - child_policy: endpointPickingPolicy, - }, - }, - ]; + if (this.lastestConfig.getLrsLoadReportingServerName()) { + childPolicy = [new LrsLoadBalancingConfig(this.lastestConfig.getCluster(), this.lastestConfig.getEdsServiceName() ?? '', this.lastestConfig.getLrsLoadReportingServerName()!, localityObj.locality, endpointPickingPolicy)]; } else { childPolicy = endpointPickingPolicy; } @@ -355,29 +399,15 @@ export class EdsLoadBalancer implements LoadBalancer { priorityChildren.set(newPriorityName, { config: [ - { - name: 'weighted_target', - weighted_target: { - targets: childTargets, - }, - }, + new WeightedTargetLoadBalancingConfig(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), - }, - }; + /* 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 list: ' + childConfig.priority.priorities); - for (const [childName, child] of childConfig.priority.children) { - trace('Child update priority config: ' + childName + ' -> ' + JSON.stringify(child)); - } + trace('Child update priority config: ' + JSON.stringify(childConfig.toJsonObject(), undefined, 2)); this.childBalancer.updateAddressList( addressList, childConfig, @@ -393,8 +423,8 @@ export class EdsLoadBalancer implements LoadBalancer { lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown } ): void { - if (!isEdsLoadBalancingConfig(lbConfig)) { - trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); + if (!(lbConfig instanceof EdsLoadBalancingConfig)) { + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2)); return; } if (!(attributes.xdsClient instanceof XdsClient)) { @@ -405,8 +435,7 @@ export class EdsLoadBalancer implements LoadBalancer { this.lastestConfig = lbConfig; this.latestAttributes = attributes; this.xdsClient = attributes.xdsClient; - const newEdsServiceName = - lbConfig.eds.edsServiceName ?? lbConfig.eds.cluster; + const newEdsServiceName = lbConfig.getEdsServiceName() ?? lbConfig.getCluster(); /* If the name is changing, disable the old watcher before adding the new * one */ @@ -429,11 +458,11 @@ export class EdsLoadBalancer implements LoadBalancer { this.isWatcherActive = true; } - if (lbConfig.eds.lrsLoadReportingServerName) { + if (lbConfig.getLrsLoadReportingServerName()) { this.clusterDropStats = this.xdsClient.addClusterDropStats( - lbConfig.eds.lrsLoadReportingServerName, - lbConfig.eds.cluster, - lbConfig.eds.edsServiceName ?? '' + lbConfig.getLrsLoadReportingServerName()!, + lbConfig.getCluster(), + lbConfig.getEdsServiceName() ?? '' ); } @@ -461,5 +490,5 @@ export class EdsLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, EdsLoadBalancer); + registerLoadBalancerType(TYPE_NAME, EdsLoadBalancer, EdsLoadBalancingConfig); } diff --git a/packages/grpc-js/src/load-balancer-lrs.ts b/packages/grpc-js-xds/src/load-balancer-lrs.ts similarity index 51% rename from packages/grpc-js/src/load-balancer-lrs.ts rename to packages/grpc-js-xds/src/load-balancer-lrs.ts index da09593b..b6fa6809 100644 --- a/packages/grpc-js/src/load-balancer-lrs.ts +++ b/packages/grpc-js-xds/src/load-balancer-lrs.ts @@ -15,28 +15,101 @@ * */ -import { - LoadBalancer, - ChannelControlHelper, - registerLoadBalancerType, - getFirstUsableConfig, -} from './load-balancer'; -import { SubchannelAddress } from './subchannel'; -import { - LoadBalancingConfig, - isLrsLoadBalancingConfig, -} from './load-balancing-config'; -import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; -import { ConnectivityState } from './channel'; -import { Picker, PickArgs, PickResultType, PickResult } from './picker'; +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 { Filter, BaseFilter, FilterFactory } from './filter'; -import { StatusObject, Call } from './call-stream'; -import { Status } from './constants'; -import { FilterStackFactory } from './filter-stack'; +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. */ @@ -132,22 +205,22 @@ export class LrsLoadBalancer implements LoadBalancer { lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown } ): void { - if (!isLrsLoadBalancingConfig(lbConfig)) { + if (!(lbConfig instanceof LrsLoadBalancingConfig)) { return; } if (!(attributes.xdsClient instanceof XdsClient)) { return; } - const lrsConfig = lbConfig.lrs; this.localityStatsReporter = attributes.xdsClient.addClusterLocalityStats( - lrsConfig.lrs_load_reporting_server_name, - lrsConfig.cluster_name, - lrsConfig.eds_service_name, - lrsConfig.locality + lbConfig.getLrsLoadReportingServerName(), + lbConfig.getClusterName(), + lbConfig.getEdsServiceName(), + lbConfig.getLocality() ); const childPolicy: LoadBalancingConfig = getFirstUsableConfig( - lrsConfig.child_policy - ) ?? { name: 'pick_first', pick_first: {} }; + lbConfig.getChildPolicy(), + true + ); this.childBalancer.updateAddressList(addressList, childPolicy, attributes); } exitIdle(): void { @@ -165,5 +238,5 @@ export class LrsLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, LrsLoadBalancer); + 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 83% rename from packages/grpc-js/src/load-balancer-priority.ts rename to packages/grpc-js-xds/src/load-balancer-priority.ts index 74f2e978..17c04812 100644 --- a/packages/grpc-js/src/load-balancer-priority.ts +++ b/packages/grpc-js-xds/src/load-balancer-priority.ts @@ -15,30 +15,24 @@ * */ -import { - LoadBalancer, - ChannelControlHelper, - getFirstUsableConfig, - registerLoadBalancerType, -} from './load-balancer'; -import { SubchannelAddress, subchannelAddressToString } 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 * as logging from './logging'; -import { LogVerbosity } from './constants'; +import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity as LogVerbosity, experimental, ChannelOptions } from '@grpc/grpc-js'; +import { validateLoadBalancingConfig } from '@grpc/grpc-js/build/src/experimental'; +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 { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); + experimental.trace(LogVerbosity.DEBUG, TRACER_NAME, text); } const TYPE_NAME = 'priority'; @@ -56,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[], @@ -384,12 +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)); + 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 @@ -427,10 +475,10 @@ 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) ?? []; @@ -483,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 75% rename from packages/grpc-js/src/load-balancer-weighted-target.ts rename to packages/grpc-js-xds/src/load-balancer-weighted-target.ts index 2da67e7f..44a6acf1 100644 --- a/packages/grpc-js/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts @@ -15,28 +15,88 @@ * */ -import { LoadBalancer, ChannelControlHelper, getFirstUsableConfig, registerLoadBalancerType } from "./load-balancer"; -import { SubchannelAddress, subchannelAddressToString } 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 * as logging from './logging'; -import { LogVerbosity } from './constants'; +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 { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); + 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. @@ -256,9 +316,9 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { } 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)); + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2)); return; } @@ -289,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); @@ -335,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/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts similarity index 84% rename from packages/grpc-js/src/resolver-xds.ts rename to packages/grpc-js-xds/src/resolver-xds.ts index 297c6c3f..814294c8 100644 --- a/packages/grpc-js/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -14,20 +14,19 @@ * limitations under the License. */ -import { Resolver, ResolverListener, registerResolver } from './resolver'; -import { GrpcUri, uriToString } from './uri-parser'; import { XdsClient } from './xds-client'; -import { ServiceConfig } from './service-config'; -import { StatusObject } from './call-stream'; -import { Status, LogVerbosity } from './constants'; -import { Metadata } from './metadata'; -import { ChannelOptions } from './channel-options'; -import * as logging from './logging'; +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 { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } class XdsResolver implements Resolver { @@ -42,7 +41,7 @@ class XdsResolver implements Resolver { private reportResolutionError() { this.listener.onError({ - code: Status.UNAVAILABLE, + code: status.UNAVAILABLE, details: `xDS name resolution failed for target ${uriToString( this.target )}`, diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js-xds/src/xds-bootstrap.ts similarity index 100% rename from packages/grpc-js/src/xds-bootstrap.ts rename to packages/grpc-js-xds/src/xds-bootstrap.ts diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts similarity index 98% rename from packages/grpc-js/src/xds-client.ts rename to packages/grpc-js-xds/src/xds-client.ts index 8b4d5d3b..525db769 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -16,19 +16,11 @@ */ import * as protoLoader from '@grpc/proto-loader'; -import { loadPackageDefinition } from './make-client'; +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 { createGoogleDefaultCredentials, ChannelCredentials } 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'; @@ -54,12 +46,15 @@ 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 } from './backoff-timeout'; +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 { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } const clientVersion = require('../../package.json').version; @@ -554,12 +549,7 @@ class RdsState implements XdsStreamState { this.watcher.onValidUpdate({ methodConfig: [], loadBalancingConfig: [ - { - name: 'cds', - cds: { - cluster: route.route.cluster, - }, - }, + new CdsLoadBalancingConfig(route.route.cluster) ], }); return; @@ -821,7 +811,7 @@ export class XdsClient { trace('Failed to initialize xDS Client. No valid credentials types found.'); // Bubble this error up to any listeners this.reportStreamError({ - code: Status.INTERNAL, + code: status.INTERNAL, details: 'Failed to initialize xDS Client. No valid credentials types found.', metadata: new Metadata(), }); @@ -846,7 +836,7 @@ export class XdsClient { trace('Failed to initialize xDS Client. ' + error.message); // Bubble this error up to any listeners this.reportStreamError({ - code: Status.INTERNAL, + code: status.INTERNAL, details: `Failed to initialize xDS Client. ${error.message}`, metadata: new Metadata(), }); diff --git a/packages/grpc-js-xds/tsconfig.json b/packages/grpc-js-xds/tsconfig.json index d1646f01..3148d112 100644 --- a/packages/grpc-js-xds/tsconfig.json +++ b/packages/grpc-js-xds/tsconfig.json @@ -2,10 +2,14 @@ "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { "rootDir": ".", - "outDir": "build" + "outDir": "build", + "target": "es2017", + "lib": ["es2017"], + "module": "commonjs", + "incremental": true }, "include": [ "src/**/*.ts", - "test/**/*.ts" + "interop/**/*.ts" ] } 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 45c4cad4..b31448c3 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -47,8 +47,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/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 ../../src grpc/testing/test.proto", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", 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/index.ts b/packages/grpc-js/src/index.ts index 89e604e3..e90ac4be 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -246,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-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index b0044d12..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; 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 56dd06f3..8d5c7c83 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -19,14 +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'; -import * as load_balancer_lrs from './load-balancer-lrs'; /** * A collection of functions associated with a channel that a load balancer @@ -102,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; } @@ -128,23 +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(); - load_balancer_lrs.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 d4d7792e..00000000 --- a/packages/grpc-js/src/load-balancing-config.ts +++ /dev/null @@ -1,271 +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. - * - */ - -import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; - -/* 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 LrsLbConfig { - cluster_name: string; - eds_service_name: string; - lrs_load_reporting_server_name: string; - locality: Locality__Output; - child_policy: LoadBalancingConfig[]; -} - -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 interface LrsLoadBalancingConfig { - name: 'lrs'; - lrs: LrsLbConfig; -} - -export type LoadBalancingConfig = - | PickFirstLoadBalancingConfig - | RoundRobinLoadBalancingConfig - | XdsLoadBalancingConfig - | GrpcLbLoadBalancingConfig - | PriorityLoadBalancingConfig - | WeightedTargetLoadBalancingConfig - | EdsLoadBalancingConfig - | CdsLoadBalancingConfig - | LrsLoadBalancingConfig; - -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'; -} - -export function isLrsLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is LrsLoadBalancingConfig { - return lbconfig.name === 'lrs'; -} - -/* 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/resolver.ts b/packages/grpc-js/src/resolver.ts index 0c4c0d6b..57c750ae 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -18,7 +18,6 @@ import { ServiceConfig } from './service-config'; import * as resolver_dns from './resolver-dns'; import * as resolver_uds from './resolver-uds'; -import * as resolver_xds from './resolver-xds'; import { StatusObject } from './call-stream'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; @@ -157,5 +156,4 @@ export function mapUriDefaultScheme(target: GrpcUri): GrpcUri | null { export function registerAll() { resolver_dns.setup(); resolver_uds.setup(); - resolver_xds.setup(); } diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 452d3c28..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, 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'; @@ -36,6 +36,7 @@ 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'; @@ -163,13 +164,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { } const workingConfigList = workingServiceConfig?.loadBalancingConfig ?? []; - if (workingConfigList.length === 0) { - workingConfigList.push({ - name: 'pick_first', - pick_first: {}, - }); - } - const loadBalancingConfig = getFirstUsableConfig(workingConfigList); + 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({ 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/tsconfig.json b/packages/grpc-js/tsconfig.json index 65ebf089..ba675db7 100644 --- a/packages/grpc-js/tsconfig.json +++ b/packages/grpc-js/tsconfig.json @@ -10,7 +10,6 @@ }, "include": [ "src/**/*.ts", - "test/**/*.ts", - "interop/**/*.ts" + "test/**/*.ts" ] } diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg index 7aae7d96..16a7dc7d 100644 --- a/test/kokoro/xds-interop.cfg +++ b/test/kokoro/xds-interop.cfg @@ -15,7 +15,7 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/packages/grpc-js/scripts/xds.sh" +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" timeout_mins: 120 action { define_artifacts { From c86f08c770655994375e2b89801db088b3e9291c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 21 Oct 2020 13:56:18 -0700 Subject: [PATCH 102/123] Document experimental namespace instability --- packages/grpc-js/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index e34cee9c..4bb4da02 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -42,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. From e05b74b631aa2b45ede14fd987c1058d54607bcc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 21 Oct 2020 14:06:14 -0700 Subject: [PATCH 103/123] Add grpc-js-xds README --- packages/grpc-js-xds/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 packages/grpc-js-xds/README.md 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 From e71caded1b81f70b9ed6f6bae6765b052e62f7c3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 21 Oct 2020 14:10:37 -0700 Subject: [PATCH 104/123] Put the google-auth-library dependency back in grpc-js --- packages/grpc-js-xds/package.json | 3 +-- packages/grpc-js/package.json | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index af6182c5..5962d42a 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -42,7 +42,6 @@ }, "dependencies": { "@grpc/grpc-js": "file:../grpc-js", - "@grpc/proto-loader": "^0.6.0-pre14", - "google-auth-library": "^6.1.1" + "@grpc/proto-loader": "^0.6.0-pre14" } } diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index b31448c3..87e10abf 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -57,6 +57,7 @@ }, "dependencies": { "@types/node": "^12.12.47", + "google-auth-library": "^6.1.1", "semver": "^6.2.0" }, "files": [ From 9699de5ec6e95e0ede257c3ad961a87963137543 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 09:59:23 -0700 Subject: [PATCH 105/123] Re-add grpc-js proto-loader dev dependency --- packages/grpc-js/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 87e10abf..2f37f7fb 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,6 +15,7 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { + "@grpc/proto-loader": "../proto-loader", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", From fd406fbef120862a945dc6719a0fb89b61756140 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 10:27:03 -0700 Subject: [PATCH 106/123] Use a regular dependency for proto-loader --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 2f37f7fb..e9019397 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,7 +15,7 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "../proto-loader", + "@grpc/proto-loader": "^0.5.5", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", From 8c112adba0038ecc12837ecaa06fb330b3231bf3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 11:21:31 -0700 Subject: [PATCH 107/123] Borrow linux job for xds tests (DO NOT MERGE) --- test/kokoro/linux.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index f40e6db4..16a7dc7d 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,10 +15,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/test/kokoro.sh" -timeout_mins: 60 +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" +timeout_mins: 120 action { define_artifacts { - regex: "github/grpc-node/reports/**/sponge_log.xml" + regex: "github/grpc/reports/**" } } From 0a4219e0b853f689e06f8fc1c0aac076e4620a6a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 13:14:13 -0700 Subject: [PATCH 108/123] Fix a directory error in the xds script --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 79c3a17a..bbfc3056 100644 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -58,7 +58,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh --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/build/interop/xds-interop-client \ + --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} \ From fba3a795c2b3af0e8a8eaed5f6cb4cd01a337732 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 14:22:51 -0700 Subject: [PATCH 109/123] Fix up grpc-js dependency --- packages/grpc-js-xds/package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 5962d42a..e22b40f5 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -31,6 +31,7 @@ }, "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", @@ -41,7 +42,9 @@ "yargs": "^15.4.1" }, "dependencies": { - "@grpc/grpc-js": "file:../grpc-js", "@grpc/proto-loader": "^0.6.0-pre14" + }, + "peerDependencies": { + "@grpc/grpc-js": "~1.2.0" } } From 261c40e51b3ab7834930f138d25a1c8e2364370b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 14:22:59 -0700 Subject: [PATCH 110/123] Revert "Borrow linux job for xds tests (DO NOT MERGE)" This reverts commit 8c112adba0038ecc12837ecaa06fb330b3231bf3. --- test/kokoro/linux.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index 16a7dc7d..f40e6db4 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,10 +15,10 @@ # 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 +build_file: "grpc-node/test/kokoro.sh" +timeout_mins: 60 action { define_artifacts { - regex: "github/grpc/reports/**" + regex: "github/grpc-node/reports/**/sponge_log.xml" } } From f312326e9cd71f5bca2f19136b31af9177f1fa9f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 23 Oct 2020 10:15:56 -0700 Subject: [PATCH 111/123] Set the default port of 80 explicitly in http_proxy --- packages/grpc-js/src/http_proxy.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 84e29a50..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; From dc80dc1f17a885e9449f2d968d4f44a013ee84fc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 23 Oct 2020 14:57:18 -0700 Subject: [PATCH 112/123] Add a simple test for the xds package to the test job --- gulpfile.ts | 11 +-- packages/grpc-js-xds/gulpfile.ts | 78 ++++++++++++++++++++++ packages/grpc-js-xds/package.json | 3 + packages/grpc-js-xds/src/index.ts | 3 + packages/grpc-js-xds/test/test-register.ts | 27 ++++++++ packages/grpc-js-xds/tsconfig.json | 1 + 6 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 packages/grpc-js-xds/gulpfile.ts create mode 100644 packages/grpc-js-xds/test/test-register.ts diff --git a/gulpfile.ts b/gulpfile.ts index 367b4d1b..a09931a1 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(jsCore.cleanAll, internalTest.cleanAll, protobuf.cleanAll, jsXds.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/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/package.json b/packages/grpc-js-xds/package.json index e22b40f5..78d90c1d 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -46,5 +46,8 @@ }, "peerDependencies": { "@grpc/grpc-js": "~1.2.0" + }, + "engines": { + "node": ">=10.10.0" } } diff --git a/packages/grpc-js-xds/src/index.ts b/packages/grpc-js-xds/src/index.ts index 5aea005d..06bea990 100644 --- a/packages/grpc-js-xds/src/index.ts +++ b/packages/grpc-js-xds/src/index.ts @@ -22,6 +22,9 @@ 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(); 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 index 3148d112..c121a5f6 100644 --- a/packages/grpc-js-xds/tsconfig.json +++ b/packages/grpc-js-xds/tsconfig.json @@ -10,6 +10,7 @@ }, "include": [ "src/**/*.ts", + "test/**/*.ts", "interop/**/*.ts" ] } From e4b69a8ee1307be15492401f6a567bb24a07368a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 28 Oct 2020 13:27:44 -0700 Subject: [PATCH 113/123] grpc-js: Add support for grpc.max_reconnect_backoff_ms channel arg --- PACKAGE-COMPARISON.md | 1 + packages/grpc-js/src/channel-options.ts | 2 ++ packages/grpc-js/src/subchannel.ts | 20 ++++++++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) 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/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index f316a58a..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; @@ -49,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/subchannel.ts b/packages/grpc-js/src/subchannel.ts index b9535769..3c607144 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -180,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 @@ -226,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); @@ -532,6 +541,9 @@ export class Subchannel { listener(); } }); + if (this.keepaliveWithoutCalls) { + this.startKeepalivePings(); + } break; case ConnectivityState.CONNECTING: this.startBackoff(); @@ -602,7 +614,9 @@ export class Subchannel { if (this.session) { this.session.ref(); } - this.startKeepalivePings(); + if (!this.keepaliveWithoutCalls) { + this.startKeepalivePings(); + } } this.callRefcount += 1; } @@ -620,7 +634,9 @@ export class Subchannel { if (this.session) { this.session.unref(); } - this.stopKeepalivePings(); + if (!this.keepaliveWithoutCalls) { + this.stopKeepalivePings(); + } this.checkBothRefcounts(); } } From e49524a2ba1c37b72635eeff08fcfd6be47cf518 Mon Sep 17 00:00:00 2001 From: Daniel Shmuglin Date: Thu, 29 Oct 2020 10:24:31 +0200 Subject: [PATCH 114/123] Server#addService - lift the limitation of adding a new service to started server --- packages/grpc-js/src/server.ts | 6 +----- packages/grpc-js/test/test-server.ts | 6 +++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 5ac25c7c..c0ced6f7 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' || @@ -637,7 +633,7 @@ async function handleUnary( if (request === undefined || call.cancelled) { return; } - + const emitter = new ServerUnaryCallImpl( call, metadata, diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 434efbbc..eb531c96 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,9 +211,9 @@ 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); } ); From 7c3ccda8fff80fe2677ca27ebf4ed7499bd58731 Mon Sep 17 00:00:00 2001 From: Daniel Shmuglin Date: Thu, 29 Oct 2020 10:54:33 +0200 Subject: [PATCH 115/123] implement Server#unregister(handlerName) --- packages/grpc-js/src/server.ts | 4 ++ packages/grpc-js/test/test-server.ts | 55 ++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index c0ced6f7..341b28bd 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -458,6 +458,10 @@ export class Server { return true; } + unregister(name: string): boolean { + return this.handlers.delete(name); + } + start(): void { if ( this.http2ServerList.length === 0 || diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index eb531c96..6a95b5cf 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -220,6 +220,61 @@ describe('Server', () => { }); }); + 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(); From 51ca00298e95f67727c9e10549e0500629f17987 Mon Sep 17 00:00:00 2001 From: Daniel Shmuglin Date: Thu, 29 Oct 2020 11:33:29 +0200 Subject: [PATCH 116/123] implement Server#unregisterService(serviceDefinition) --- packages/grpc-js/src/server.ts | 15 +++++++ packages/grpc-js/test/test-server.ts | 61 ++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 341b28bd..28599160 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -208,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'); } diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 6a95b5cf..58b10288 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -220,6 +220,67 @@ describe('Server', () => { }); }); + 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; From ae2b64bd659a74adcca0c48d1cefc6aa252795cf Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 30 Oct 2020 11:38:30 -0700 Subject: [PATCH 117/123] grpc-js: Implement deadline and cancellation propagation --- packages/grpc-js/src/call-stream.ts | 16 +- packages/grpc-js/src/channel.ts | 14 +- packages/grpc-js/src/client-interceptors.ts | 20 +- packages/grpc-js/src/constants.ts | 3 +- packages/grpc-js/src/server-call.ts | 34 ++- .../grpc-js/test/test-call-propagation.ts | 253 ++++++++++++++++++ 6 files changed, 310 insertions(+), 30 deletions(-) create mode 100644 packages/grpc-js/test/test-call-propagation.ts diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index fd50a807..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() { @@ -623,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 { diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index dcfae483..05588c49 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -28,7 +28,7 @@ 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'; @@ -39,6 +39,8 @@ 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 { CONNECTING, @@ -118,7 +120,7 @@ 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; } @@ -509,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') { @@ -537,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/server-call.ts b/packages/grpc-js/src/server-call.ts index 2c62b206..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,6 +78,7 @@ export type ServerSurfaceCall = { readonly metadata: Metadata; getPeer(): string; sendMetadata(responseMetadata: Metadata): void; + getDeadline(): Deadline; } & EventEmitter; export type ServerUnaryCall = ServerSurfaceCall & { @@ -120,6 +121,10 @@ export class ServerUnaryCallImpl extends EventEmitter sendMetadata(responseMetadata: Metadata): void { this.call.sendMetadata(responseMetadata); } + + getDeadline(): Deadline { + return this.call.getDeadline(); + } } export class ServerReadableStreamImpl @@ -153,6 +158,10 @@ export class ServerReadableStreamImpl sendMetadata(responseMetadata: Metadata): void { this.call.sendMetadata(responseMetadata); } + + getDeadline(): Deadline { + return this.call.getDeadline(); + } } export class ServerWritableStreamImpl @@ -186,6 +195,10 @@ export class ServerWritableStreamImpl this.call.sendMetadata(responseMetadata); } + getDeadline(): Deadline { + return this.call.getDeadline(); + } + _write( chunk: ResponseType, encoding: string, @@ -257,6 +270,10 @@ export class ServerDuplexStreamImpl extends Duplex this.call.sendMetadata(responseMetadata); } + getDeadline(): Deadline { + return this.call.getDeadline(); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any end(metadata?: any) { if (metadata) { @@ -357,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; @@ -405,7 +423,7 @@ export class Http2ServerCallStream< } // Clear noop timer - clearTimeout(this.deadline); + clearTimeout(this.deadlineTimer); } private checkCancelled(): boolean { @@ -452,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); } @@ -566,7 +586,7 @@ export class Http2ServerCallStream< statusObj.details ); - clearTimeout(this.deadline); + clearTimeout(this.deadlineTimer); if (!this.wantTrailers) { this.wantTrailers = true; @@ -779,6 +799,10 @@ export class Http2ServerCallStream< return 'unknown'; } } + + getDeadline(): Deadline { + return this.deadline; + } } /* eslint-disable @typescript-eslint/no-explicit-any */ 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 From 62e5038fcccd1c2749ab29e82b33a9093750f967 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Nov 2020 10:10:07 -0800 Subject: [PATCH 118/123] Reorder gulp cleanup step to avoid breakages --- gulpfile.ts | 2 +- packages/grpc-js-xds/src/load-balancer-priority.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gulpfile.ts b/gulpfile.ts index a09931a1..7ac4e9a0 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -34,7 +34,7 @@ const setupPureJSInterop = gulp.series(jsCore.install, protobuf.install, interna const clean = gulp.series(jsCore.clean, protobuf.clean, jsXds.clean); -const cleanAll = gulp.series(jsCore.cleanAll, internalTest.cleanAll, protobuf.cleanAll, jsXds.cleanAll); +const cleanAll = gulp.series(jsXds.cleanAll, jsCore.cleanAll, internalTest.cleanAll, protobuf.cleanAll); const nativeTestOnly = gulp.parallel(healthCheck.test); diff --git a/packages/grpc-js-xds/src/load-balancer-priority.ts b/packages/grpc-js-xds/src/load-balancer-priority.ts index 17c04812..872ed7d1 100644 --- a/packages/grpc-js-xds/src/load-balancer-priority.ts +++ b/packages/grpc-js-xds/src/load-balancer-priority.ts @@ -16,7 +16,7 @@ */ import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity as LogVerbosity, experimental, ChannelOptions } from '@grpc/grpc-js'; -import { validateLoadBalancingConfig } from '@grpc/grpc-js/build/src/experimental'; +import validateLoadBalancingConfig = experimental.validateLoadBalancingConfig; import LoadBalancer = experimental.LoadBalancer; import ChannelControlHelper = experimental.ChannelControlHelper; import getFirstUsableConfig = experimental.getFirstUsableConfig; From b31fc293da4bd04e21622acfbdd962a4d4ab67f8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 5 Nov 2020 13:08:50 -0800 Subject: [PATCH 119/123] Skip non-working test, test JS-JS interop first --- test/api/interop_extra_test.js | 5 ++++- test/gulpfile.ts | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index c7411c17..ab686e14 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -170,7 +170,10 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio assert.ifError(error); }); }); - it('should be able to send very large headers and trailers', function(done) { + /* 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)); 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 { From cd2713f42a743cc3c48ffa9519b8c53a90671dea Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 9 Nov 2020 10:45:57 -0800 Subject: [PATCH 120/123] grpc-js: Rearrange connectivity state enum to match the native library --- packages/grpc-js/src/channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index dcfae483..5f49c764 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -41,10 +41,10 @@ import { mapProxyName } from './http_proxy'; import { GrpcUri, parseUri, uriToString } from './uri-parser'; export enum ConnectivityState { + IDLE, CONNECTING, READY, TRANSIENT_FAILURE, - IDLE, SHUTDOWN, } From adfd4db9eaf4fc498067054179ba9fddf167a5e6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 9 Nov 2020 10:53:44 -0800 Subject: [PATCH 121/123] grpc-js: Update to 1.2.0 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index e9019397..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.7", + "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", From ccb85ba470e9b244d23a36fc5d5e447e467e4d3e Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Wed, 18 Nov 2020 16:01:08 +0900 Subject: [PATCH 122/123] Bump protobuf dep to v3.14.0 --- packages/grpc-tools/deps/protobuf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From c981d2cec351f043497a6ee3358897172f0b2360 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 18 Nov 2020 11:25:02 -0800 Subject: [PATCH 123/123] grpc-tools: Bump version to 1.10.0 --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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/",