Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

router: integrate matching API #17633

Merged
merged 55 commits into from
Oct 13, 2021
Merged

router: integrate matching API #17633

merged 55 commits into from
Oct 13, 2021

Conversation

snowp
Copy link
Contributor

@snowp snowp commented Aug 9, 2021

Adds support for using the matching API in the route table. This wires up using the generic match as part of a virtual host, making
it possible to define a match tree that results in Route actions that reuses the same routing actions currently in use by the router.

Risk Level: Medium, refactors route config but should be a net new feature
Testing: UTs (needs integration testing)
Docs Changes: Updates to the http_routing and matching_api docs
Release Notes: n/a (will add)
Platform Specific Features: n/a

snowp added 30 commits June 17, 2021 13:02
Prior to this PR the MatchTreeFactory requried a ServerFactoryContext in
order to pass this to the action factories. This is not available in all
contexts, and there are other possible use cases where we might need
to pass additional information to the match tree factory (e.g. the
router might need to pass the parent vhost configuration).

This PR introduces a paramterized action context, allowing each usage of
the MatchTree to define its own data that should be presented to the
action factories. This also has the nice benefit of partitioning the
action factories per context: each unique ActionFactoryContext defines a
new factory type, ensuring that actions defined for a HTTP filter
context won't be conflated with actions defined for another context.

Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
…matcher

Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
…matcher

Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
@mattklein123
Copy link
Member

The main open question that remains imo is around whether we should runtime guard this like we do for ExtensionWithMatcher, or if we're at a point where we feel like we can enable the matching API without an explicit opt in (in which case we should probably remove the runtime flag requirement from ExtensionWithMatcher).

Per offline convo, my mild preference is to mark use of this field as experimental and exempt from CVE handling, and force opt-in via a runtime variable. This can be used for initial testing. Once we feel it's gotten a bit of use we can remove the gate.

Open to suggestions (probably from @mattklein123) about what kind of test coverage we want here. The majority of the routing logic is still the old code, so the single test I have that demonstrates that we can resolve the route covers all the new code paths, but perhaps we want to verify other flows.

I think as long as we have coverage of the new code it's probably fine, but just for completeness I would try to have some integration tests of the sub-linear matching flows if possible?

Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
@snowp snowp marked this pull request as ready for review September 2, 2021 16:55
@snowp
Copy link
Contributor Author

snowp commented Sep 3, 2021

This should be ready for code review now

Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks very cool. Can you add more tests for some of the configuration error cases so it's easier to understand the error flows?

/wait

}
if (virtual_host.has_matcher() &&
!Runtime::runtimeFeatureEnabled("envoy.reloadable_features.experimental_matching_api")) {
throw EnvoyException("Experimental matching API is not enabled");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make this error message more expressive such as which runtime key to set, etc.?

} else {
for (const auto& route : virtual_host.routes()) {
if (!route.has_match()) {
throw EnvoyException("RouteValidationError.Match");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this error mean? Can you make it more descriptive and also maybe add more comments here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually don't think we need this any more after we moved to evaluating the resolved Route, let me just remove this

auto match = Matcher::evaluateMatch<Http::HttpMatchingData>(*matcher_, data);

if (match.result_) {
ASSERT(dynamic_cast<RouteMatchAction*>(match.result_.get()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment on where this is validated?

Comment on lines 1485 to 1486
// TODO(snowp): Add logger
// ENVOY_LOG(debug, "failed to match incoming request: {}", match.result_);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just do this now?

the match criteria of the resolved Route. Path matching done during the match tree traversal does not contribute
to path rewrites.

The only inputs supported are request headers (via `envoy.type.matcher.v3.HttpRequestHeaderMatchInput`). See
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this validated and what error message does the user get if they configure something else accidentally?

Same question about the action config which I guess will only currently work for route proto lookup?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like this was not validated, now we are with the following error message:

requirement violation while creating route match tree: INVALID_ARGUMENT: Route table can only match on request headers, saw type.googleapis.com/envoy.type.matcher.v3.HttpResponseHeaderMatchInput

For action configs the only registered factory for ActionFactory<RouteActionContext> is RouteMatchActionFactory, so all others would result in the typical "no factory found"

Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
snowp added 3 commits October 9, 2021 03:35
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks excited to see this land. One small comment.

/wait

Comment on lines 100 to 101
// Note that this API is a work in progress and must be explicitly enabled by setting the runtime
// "envoy.reloadable_features.experimental_matching_api" to "true".
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we don't need this anymore given the WIP annotation and the warning about this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure yeah I'll happily remove this. Might also be okay to remove this flag requirement from the filter integration as well? Can do that in a follow up, would love to get this PR in

Signed-off-by: Snow Pettersen <snowp@lyft.com>
Copy link
Member

@mattklein123 mattklein123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Awesome work! Fine to do the other removal in a follow up.

@snowp snowp merged commit 94d0013 into envoyproxy:main Oct 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants