Skip to content

Commit

Permalink
router: scoped rds (2a): scoped routing configuration protos (#6675)
Browse files Browse the repository at this point in the history
Protos to statically and dynamically (via the Scoped Route Discovery Service) configure scoped
routing logic in Envoy.

Signed-off-by: Andres Guedez <[email protected]>
  • Loading branch information
AndresGuedez authored and mattklein123 committed Apr 26, 2019
1 parent 4b0ba22 commit 2778c3c
Show file tree
Hide file tree
Showing 7 changed files with 289 additions and 1 deletion.
21 changes: 21 additions & 0 deletions api/envoy/api/v2/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,24 @@ api_go_grpc_library(
"//envoy/api/v2/route:route_go_proto",
],
)

api_proto_library_internal(
name = "srds",
srcs = ["srds.proto"],
has_services = 1,
visibility = [":friends"],
deps = [
":discovery",
"//envoy/api/v2/core:base",
"//envoy/api/v2/route",
],
)

api_go_grpc_library(
name = "srds",
proto = ":srds",
deps = [
":discovery_go_proto",
"//envoy/api/v2/core:base_go_proto",
],
)
142 changes: 142 additions & 0 deletions api/envoy/api/v2/srds.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
syntax = "proto3";

package envoy.api.v2;

option java_outer_classname = "SrdsProto";
option java_package = "io.envoyproxy.envoy.api.v2";
option java_multiple_files = true;
option java_generic_services = true;

import "envoy/api/v2/discovery.proto";

import "google/api/annotations.proto";

import "validate/validate.proto";
import "gogoproto/gogo.proto";

option (gogoproto.equal_all) = true;

// [#protodoc-title: HTTP scoped routing configuration]
// * Routing :ref:`architecture overview <arch_overview_http_routing>`
//
// .. attention::
//
// The Scoped RDS API is not yet fully implemented and *should not* be enabled in
// :ref:`envoy_api_msg_config.filter.network.http_connection_manager.v2.HttpConnectionManager`.
//
// TODO(AndresGuedez): Update :ref:`arch_overview_http_routing` with scoped routing overview and
// configuration details.

// The Scoped Routes Discovery Service (SRDS) API distributes
// :ref:`ScopedRouteConfiguration<envoy_api_msg.ScopedRouteConfiguration>` resources. Each
// ScopedRouteConfiguration resource represents a "routing scope" containing a mapping that allows
// the HTTP connection manager to dynamically assign a routing table (specified via
// a :ref:`RouteConfiguration<envoy_api_msg_RouteConfiguration>` message) to each HTTP request.
// [#proto-status: experimental]
service ScopedRoutesDiscoveryService {
rpc StreamScopedRoutes(stream DiscoveryRequest) returns (stream DiscoveryResponse) {
}

rpc DeltaScopedRoutes(stream DeltaDiscoveryRequest) returns (stream DeltaDiscoveryResponse) {
}

rpc FetchScopedRoutes(DiscoveryRequest) returns (DiscoveryResponse) {
option (google.api.http) = {
post: "/v2/discovery:scoped-routes"
body: "*"
};
}
}

// 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.
//
// [#comment:next free field: 4]
// [#proto-status: experimental]
message ScopedRouteConfiguration {
// The name assigned to the routing scope.
string name = 1 [(validate.rules).string.min_bytes = 1];

// 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.
message Key {
message Fragment {
oneof type {
option (validate.required) = true;

// A string to match against.
string string_key = 1;
}
}

// 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>`.
repeated Fragment fragments = 1 [(validate.rules).repeated .min_items = 1];
}

// 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.
string route_configuration_name = 2 [(validate.rules).string.min_bytes = 1];

// The key to match against.
Key key = 3 [(validate.rules).message.required = true];
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ api_proto_library_internal(
srcs = ["http_connection_manager.proto"],
deps = [
"//envoy/api/v2:rds",
"//envoy/api/v2:srds",
"//envoy/api/v2/core:base",
"//envoy/api/v2/core:config_source",
"//envoy/api/v2/core:protocol",
Expand All @@ -20,6 +21,7 @@ api_go_proto_library(
proto = ":http_connection_manager",
deps = [
"//envoy/api/v2:rds_go_grpc",
"//envoy/api/v2:srds_go_grpc",
"//envoy/api/v2/core:base_go_proto",
"//envoy/api/v2/core:config_source_go_proto",
"//envoy/api/v2/core:protocol_go_proto",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ option go_package = "v2";
import "envoy/api/v2/core/config_source.proto";
import "envoy/api/v2/core/protocol.proto";
import "envoy/api/v2/rds.proto";
import "envoy/api/v2/srds.proto";
import "envoy/config/filter/accesslog/v2/accesslog.proto";
import "envoy/type/percent.proto";

Expand All @@ -24,7 +25,7 @@ import "gogoproto/gogo.proto";
// [#protodoc-title: HTTP connection manager]
// HTTP connection manager :ref:`configuration overview <config_http_conn_man>`.

// [#comment:next free field: 31]
// [#comment:next free field: 32]
message HttpConnectionManager {
enum CodecType {
option (gogoproto.goproto_enum_prefix) = false;
Expand Down Expand Up @@ -61,6 +62,11 @@ message HttpConnectionManager {

// The route table for the connection manager is static and is specified in this property.
envoy.api.v2.RouteConfiguration route_config = 4;

// 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.
ScopedRoutes scoped_routes = 31;
}

// A list of individual HTTP filters that make up the filter chain for
Expand Down Expand Up @@ -419,6 +425,119 @@ message Rds {
string route_config_name = 2 [(validate.rules).string.min_bytes = 1];
}

// This message is used to work around the limitations with 'oneof' and repeated fields.
message ScopedRouteConfigurationsList {
repeated envoy.api.v2.ScopedRouteConfiguration scoped_route_configurations = 1
[(validate.rules).repeated .min_items = 1];
}

message ScopedRoutes {
// The name assigned to the scoped routing configuration.
string name = 1 [(validate.rules).string.min_bytes = 1];

// 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.
message ScopeKeyBuilder {
// Specifies the mechanism for constructing key fragments which are composed into scope keys.
message FragmentBuilder {
// 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.
message HeaderValueExtractor {
// The name of the header field to extract the value from.
string name = 1 [(validate.rules).string.min_bytes = 1];

// 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.
string element_separator = 2;

// Specifies a header field's key value pair to match on.
message KvElement {
// The separator between key and value (e.g., '=' separates 'k=v;...').
string separator = 1 [(validate.rules).string.min_bytes = 1];

// The key to match on.
string key = 2 [(validate.rules).string.min_bytes = 1];
}

oneof extract_type {
// Specifies the zero based index of the element to extract.
uint32 index = 3;

// Specifies the key value pair to extract the value from.
KvElement element = 4;
}
}

oneof type {
option (validate.required) = true;

// Specifies how a header field's value should be extracted.
HeaderValueExtractor header_value_extractor = 1;
}
}

// The final scope key consists of the ordered union of these fragments.
repeated FragmentBuilder fragments = 1 [(validate.rules).repeated .min_items = 1];
}

// The algorithm to use for constructing a scope key for each request.
ScopeKeyBuilder scope_key_builder = 2 [(validate.rules).message.required = true];

// Configuration source specifier for RDS.
// This config source is used to subscribe to RouteConfiguration resources specified in
// ScopedRouteConfiguration messages.
envoy.api.v2.core.ConfigSource rds_config_source = 3
[(validate.rules).message.required = true, (gogoproto.nullable) = false];

oneof config_specifier {
option (validate.required) = true;

// 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.
ScopedRouteConfigurationsList scoped_route_configurations_list = 4;

// 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.
ScopedRds scoped_rds = 5;
}
}

message ScopedRds {
// Configuration source specifier for scoped RDS.
envoy.api.v2.core.ConfigSource scoped_rds_config_source = 1
[(validate.rules).message.required = true, (gogoproto.nullable) = false];
}

message HttpFilter {
// The name of the filter to instantiate. The name must match a supported
// filter. The built-in filters are:
Expand Down
1 change: 1 addition & 0 deletions docs/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ PROTO_RST="
/envoy/api/v2/cluster/circuit_breaker/envoy/api/v2/cluster/circuit_breaker.proto.rst
/envoy/api/v2/rds/envoy/api/v2/rds.proto.rst
/envoy/api/v2/route/route/envoy/api/v2/route/route.proto.rst
/envoy/api/v2/srds/envoy/api/v2/srds.proto.rst
/envoy/api/v2/lds/envoy/api/v2/lds.proto.rst
/envoy/api/v2/listener/listener/envoy/api/v2/listener/listener.proto.rst
/envoy/api/v2/ratelimit/ratelimit/envoy/api/v2/ratelimit/ratelimit.proto.rst
Expand Down
1 change: 1 addition & 0 deletions docs/root/api-v2/http_routes/http_routes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ HTTP route management
:maxdepth: 2

../api/v2/rds.proto
../api/v2/srds.proto
../api/v2/route/route.proto
2 changes: 2 additions & 0 deletions tools/spelling_dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ SPIFFE
SPKI
SQL
SR
SRDS
SRV
SS
SSL
Expand Down Expand Up @@ -274,6 +275,7 @@ WS
Welford's
Werror
XDS
vip
xDSes
XFCC
XFF
Expand Down

0 comments on commit 2778c3c

Please sign in to comment.