mirror of https://github.com/grpc/grpc-node.git
Merge pull request #1522 from murgatroid99/grpc-js_xds_resolver
grpc-js: Add XdsResolver and corresponding XdsClient behavior
This commit is contained in:
commit
2388e31f8d
|
@ -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",
|
||||
|
|
|
@ -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';
|
||||
|
@ -220,20 +219,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),
|
||||
|
|
|
@ -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<envoy_api_field_config.filter.network.http_connection_manager.v2.ScopedRoutes.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<envoy_api_field_config.filter.network.http_connection_manager.v2.ScopedRoutes.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<envoy_api_field_config.filter.network.http_connection_manager.v2.ScopedRoutes.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<envoy_api_field_config.filter.network.http_connection_manager.v2.ScopedRoutes.scope_key_builder>`.
|
||||
*/
|
||||
'fragments': (_envoy_api_v2_ScopedRouteConfiguration_Key_Fragment__Output)[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifies a routing scope, which associates a
|
||||
* :ref:`Key<envoy_api_msg_ScopedRouteConfiguration.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<envoy_api_field_config.filter.network.http_connection_manager.v2.ScopedRoutes.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<envoy_api_field_config.filter.network.http_connection_manager.v2.ScopedRoutes.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<envoy_api_msg_ScopedRouteConfiguration.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<envoy_api_field_config.filter.network.http_connection_manager.v2.ScopedRoutes.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<envoy_api_field_config.filter.network.http_connection_manager.v2.ScopedRoutes.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);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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 <config_http_filters>`.
|
||||
*/
|
||||
'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 <config_http_filters>`.
|
||||
*/
|
||||
'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";
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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)[];
|
||||
}
|
|
@ -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
|
||||
* | || |
|
||||
* | || \----> <element_separator>
|
||||
* | ||
|
||||
* | |\----> <element.separator>
|
||||
* | |
|
||||
* | \----> <element.key>
|
||||
* |
|
||||
* \----> <name>
|
||||
*
|
||||
* 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
|
||||
* | || |
|
||||
* | || \----> <element_separator>
|
||||
* | ||
|
||||
* | |\----> <element.separator>
|
||||
* | |
|
||||
* | \----> <element.key>
|
||||
* |
|
||||
* \----> <name>
|
||||
*
|
||||
* 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<envoy_api_msg_ScopedRouteConfiguration.Key>`
|
||||
* objects assembled from :ref:`ScopedRouteConfiguration<envoy_api_msg_ScopedRouteConfiguration>`
|
||||
* messages distributed via SRDS (the Scoped Route Discovery Service) or assigned statically via
|
||||
* :ref:`scoped_route_configurations_list<envoy_api_field_config.filter.network.http_connection_manager.v2.ScopedRoutes.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<envoy_api_msg_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<envoy_api_msg_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<envoy_api_msg_ScopedRouteConfiguration.Key>`
|
||||
* objects assembled from :ref:`ScopedRouteConfiguration<envoy_api_msg_ScopedRouteConfiguration>`
|
||||
* messages distributed via SRDS (the Scoped Route Discovery Service) or assigned statically via
|
||||
* :ref:`scoped_route_configurations_list<envoy_api_field_config.filter.network.http_connection_manager.v2.ScopedRoutes.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<envoy_api_msg_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<envoy_api_msg_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<envoy_api_msg_config.filter.network.http_connection_manager.v2.ScopedRoutes.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<envoy_api_msg_config.filter.network.http_connection_manager.v2.ScopedRoutes.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<envoy_api_msg_config.filter.network.http_connection_manager.v2.ScopedRoutes.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<envoy_api_msg_config.filter.network.http_connection_manager.v2.ScopedRoutes.ScopeKeyBuilder>`
|
||||
* in this message.
|
||||
*/
|
||||
'scoped_rds'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRds__Output);
|
||||
'config_specifier': "scoped_route_configurations_list"|"scoped_rds";
|
||||
}
|
|
@ -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 <envoy_api_msg_config.filter.network.http_connection_manager.v2.HttpConnectionManager.Tracing>`
|
||||
* :ref:`provider <envoy_api_field_config.filter.network.http_connection_manager.v2.HttpConnectionManager.Tracing.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 <envoy_api_msg_config.trace.v2.LightstepConfig>`
|
||||
* - :ref:`ZipkinConfig <envoy_api_msg_config.trace.v2.ZipkinConfig>`
|
||||
* - :ref:`DynamicOtConfig <envoy_api_msg_config.trace.v2.DynamicOtConfig>`
|
||||
* - :ref:`DatadogConfig <envoy_api_msg_config.trace.v2.DatadogConfig>`
|
||||
* - :ref:`OpenCensusConfig <envoy_api_msg_config.trace.v2.OpenCensusConfig>`
|
||||
* - :ref:`AWS X-Ray <envoy_api_msg_config.trace.v2alpha.XRayConfig>`
|
||||
*/
|
||||
'config_type'?: "config"|"typed_config";
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for an HTTP tracer provider used by Envoy.
|
||||
*
|
||||
* The configuration is defined by the
|
||||
* :ref:`HttpConnectionManager.Tracing <envoy_api_msg_config.filter.network.http_connection_manager.v2.HttpConnectionManager.Tracing>`
|
||||
* :ref:`provider <envoy_api_field_config.filter.network.http_connection_manager.v2.HttpConnectionManager.Tracing.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 <envoy_api_msg_config.trace.v2.LightstepConfig>`
|
||||
* - :ref:`ZipkinConfig <envoy_api_msg_config.trace.v2.ZipkinConfig>`
|
||||
* - :ref:`DynamicOtConfig <envoy_api_msg_config.trace.v2.DynamicOtConfig>`
|
||||
* - :ref:`DatadogConfig <envoy_api_msg_config.trace.v2.DatadogConfig>`
|
||||
* - :ref:`OpenCensusConfig <envoy_api_msg_config.trace.v2.OpenCensusConfig>`
|
||||
* - :ref:`AWS X-Ray <envoy_api_msg_config.trace.v2alpha.XRayConfig>`
|
||||
*/
|
||||
'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 <envoy_api_msg_config.trace.v2.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 <envoy_api_msg_config.trace.v2.Tracing.Http>`.
|
||||
*/
|
||||
export interface Tracing__Output {
|
||||
/**
|
||||
* Provides configuration for the HTTP tracer.
|
||||
*/
|
||||
'http'?: (_envoy_config_trace_v2_Tracing_Http__Output);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,228 @@
|
|||
import * as grpc from '../index';
|
||||
import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader';
|
||||
|
||||
|
||||
type ConstructorArguments<Constructor> = Constructor extends new (...args: infer Args) => any ? Args: never;
|
||||
type SubtypeConstructor<Constructor, Subtype> = {
|
||||
new(...args: ConstructorArguments<Constructor>): 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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)}`
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -415,7 +415,7 @@ export class Server {
|
|||
},
|
||||
};
|
||||
|
||||
const resolver = createResolver(portUri, resolverListener);
|
||||
const resolver = createResolver(portUri, resolverListener, this.options);
|
||||
resolver.updateResolution();
|
||||
}
|
||||
|
||||
|
|
|
@ -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<ServiceConfig>,
|
||||
|
@ -308,6 +327,155 @@ 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'] === 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();
|
||||
}
|
||||
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 +492,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 +505,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 +584,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 +640,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 +707,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 +751,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 +821,26 @@ export class XdsClient {
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
});
|
||||
}
|
||||
|
||||
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() {
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue