docs: document HTTP generic matching#14864
Conversation
Signed-off-by: Snow Pettersen <snowp@lyft.com>
htuch
left a comment
There was a problem hiding this comment.
Super excited to see this land as a user facing feature :) I've left a lot of nits, but the docs looks great.
/wait
|
|
||
| // Indicates that the associated filter should be skipped. | ||
| // Configuration for the SkipFilter match action. When matching results in this action, the | ||
| // associated filter will be ignored going for all data callbacks (including the one that |
There was a problem hiding this comment.
Maybe "ignored for all data callbacks" rather than "ignored going".
| // Configuration for the SkipFilter match action. When matching results in this action, the | ||
| // associated filter will be ignored going for all data callbacks (including the one that | ||
| // triggered the match result). As a result, if this matching is done on the first data | ||
| // callback (e.g. request headers), this will completely skip the filter. |
There was a problem hiding this comment.
This is the first time the concept of "data callback" comes up. Is there a way to explain it more clearly?
What happens when the matcher is used in a non-HTTP filter context? E.g. in some new router scheme. I guess HTTP filter callbacks still apply there, but what about TAP, etc.?
There was a problem hiding this comment.
In my mind this would only be used in the context of HTTP filters (hence the name SkipFilter). Right now we don't have a mechanism to allowlist which actions can be used in various contexts, but I imagine we'll want this or some kind of template trickery to create unique sets of actions for different contexts.
I've removed the use of "data callback", hopefully this will be easier to understand now
| // Filter specific configuration which depends on the filter being instantiated. See the supported | ||
| // filters for further documentation. | ||
| // | ||
| // To support configuring a :ref:`match tree <arch_overview_matching_api>`, use a |
There was a problem hiding this comment.
Nit: s/a/an/ here and below before ExtensionWithMatcher.
|
|
||
| Envoy makes use of a matching API to allow the various subsystems to express actions that should be performed based on incoming data. | ||
|
|
||
| The matching API is designed as a tree structure to allow for sublinear matching algorithms, and make heavy use of extension points to make it |
There was a problem hiding this comment.
Nit: "makes heave use". I'd also maybe say "for performance better than linear list matching as seen in Envoy's HTTP routing" or the like to clearly provide the bogeyman that is at stake.
| Within supported environments (currently only HTTP filters), a wrapper proto can be used to instantiate a matching filter associated with the | ||
| wrapped structure: | ||
|
|
||
| .. code-block:: yaml |
There was a problem hiding this comment.
@phlax should this be a verified code example? Can we generally just enable this for all new code fragments?
There was a problem hiding this comment.
the code that i have added verification for so far were complete configurations which are then added to the rst with literalinclude
we could just separate this into yaml and validate just that, or we could wrap this example in a complete config and just highlight the important parts
There was a problem hiding this comment.
Do I get validation for free just by following the literalinclude pattern used elsewhere? Or do I need to do anything else?
It's easy enough to include enough config to make it a valid config, so if we can easily validate the config by doing that then I think it's worth it
There was a problem hiding this comment.
its kinda the other way round in a sense
if you separate the config it will automatically get validated unless its specifically excluded
There was a problem hiding this comment.
...at least for the envoy config - not sure about any yaml validation
There was a problem hiding this comment.
Do I get validation for free just by following the literalinclude pattern used elsewhere? Or do I need to do anything else?
so, yep
| typed_config: | ||
| "@type": type.googleapis.com/envoy.extensions.filters.common.matcher.action.v3.SkipFilter | ||
|
|
||
| The above example wraps a HTTP filter (the SetResponseCode filter) in an ExtensionWithMatcher, allowing us to define |
There was a problem hiding this comment.
Nit: prefer some RST formatting for filer proper names, e.g. *SetResponseCode*.
There was a problem hiding this comment.
should this be a link to the relevant filter?
| A consequence of this is that if the filter wishes to gate some behavior on a match result, it has to manage stopping the iteration on its own. | ||
|
|
||
| When it comes to actions such as SkipFilter, this means that if the skip condition is based on anything but the request headers, the filter might | ||
| get partially applied until the match result is ready. This might result in surprising beahvior. No newline at end of file |
There was a problem hiding this comment.
Surprises are fun :) Is there a way to call out some concrete examples of where this happens?
There was a problem hiding this comment.
Sure I'll dig through and find an explicit example.
Down the line I would like to use #14727 to make it possible for filters to codify these to cause config rejection instead of these surprises, but this is what we've got for now
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>
|
This should be ready for another pass @htuch |
|
|
||
| // Indicates that the associated filter should be skipped. | ||
| // Configuration for the SkipFilter match action. When matching results in this action, the | ||
| // associated filter will be ignored for all filter callbacks (e.g. encodeHeaders, encodeData, |
There was a problem hiding this comment.
Nit: RST markup for function literals.
| // | ||
| // To support configuring a :ref:`match tree <arch_overview_matching_api>`, use an | ||
| // :ref:`ExtensionWithMatcher <envoy_api_msg_extensions.common.matching.v3.ExtensionWithMatcher>` | ||
| // with the desired HTTP filter. This work for both the default filter configuration as well as for filters provided via the API. |
There was a problem hiding this comment.
| // with the desired HTTP filter. This work for both the default filter configuration as well as for filters provided via the API. | |
| // with the desired HTTP filter. This works for both the default filter configuration as well as for filters provided via the API. |
|
|
||
| The above example wraps a HTTP filter (the | ||
| :ref:`HTTPFault <envoy_v3_api_msg_extensions.filters.http.fault.v3.HttpFault>` filter) in an | ||
| ExtensionWithMatcher, allowing us to define a match tree to be evaluated in conjunction with |
| exact_match_map: | ||
| # Note this additional indirection; this is a workaround for Protobuf oneof limitations. | ||
| map: | ||
| skip_filter: # This is the header value we're trying to match against. |
There was a problem hiding this comment.
It's a little confusing seeing both action name skip and the key here being skip_filter. Could the key (which is header value) be "some_value_to_match_on" or something like that?
| "@type": type.googleapis.com/envoy.type.matcher.v3.HttpRequestHeaderMatchInput | ||
| header_name: second-header | ||
| value_match: | ||
| exact: bar |
There was a problem hiding this comment.
A non-actionable comment that maybe we can just discuss thoughts on; the verbosity here is so high that I think we have two issues from a practical perspective:
- Users who hand-write config are probably going to never want to use complex matchers. I feel the only way to use this reasonably is with some frontend language or API.
- The config size is going to blow out at scale when we have type URL appearing everywhere. We've seen this also when looking at the impact of
xdstp://URLs. It would be ironic if a solution aimed at scalability has a high cost due to config size explosion. I think for this problem we can maybe just add in some fixed matchers over time that take the place of common operations. This can be future work, but I think at scale it might be needed (e.g. a route table with 100k entries).
There was a problem hiding this comment.
For 1 I agree that people are probably never going to write complicated trees by hand: even for existing APIs most the advanced use cases are probably written at least using protobuf intellisense/autocomplete. Do you think this example ends up being too complicated to be useful?
I think this is a valid concern, though the config size explosion mostly matters at config update, not stream processing. At some point it can become an issue (CPU usage, delayed config application) but I don't think it would directly affect data plane performance. I wonder if it makes sense to reuse the pattern of static SDS secrets where we could define named extensions somewhere and then simply reference them by name in config instead of repeating the whole configuration. That would avoid the explosion in cases where the exact same matcher/input is used in a lot of different branches
There was a problem hiding this comment.
Not arguing against including the example, just sharing some food for thought. I agree the cost is only at config update, that's where we're seeing real CPU costs at O(10k) cluster or route configs.
We've been thinking even about templating to make xdstp:// names work better, I'll keep this use case in mind as well when thinking through that.
| When it comes to actions such as SkipFilter, this means that if the skip condition is based on anything but the request headers, the filter might | ||
| get partially applied until the match result is ready. This might result in surprising beahvior. An example of this would be to have a matching | ||
| tree that attempts to skip the gRPC-Web filter based on response headers: since the gRPC-Web filter will transform incoming requests into gRPC proper, | ||
| clients will generally assume that the gRPC -> gRPC-Web transformation will happen on the encoding side. By causing the filter to once the response |
There was a problem hiding this comment.
Not sure about how to parse "By causing the filter to once the .."
| A consequence of this is that if the filter wishes to gate some behavior on a match result, it has to manage stopping the iteration on its own. | ||
|
|
||
| When it comes to actions such as SkipFilter, this means that if the skip condition is based on anything but the request headers, the filter might | ||
| get partially applied until the match result is ready. This might result in surprising beahvior. An example of this would be to have a matching |
There was a problem hiding this comment.
| get partially applied until the match result is ready. This might result in surprising beahvior. An example of this would be to have a matching | |
| get partially applied until the match result is ready. This might result in surprising behavior. An example of this would be to have a matching |
Signed-off-by: Snow Pettersen <snowp@lyft.com>
| address: | ||
| socket_address: | ||
| address: 127.0.0.1 | ||
| port_value: 8080 No newline at end of file |
There was a problem hiding this comment.
i think this should have a new line
| address: | ||
| socket_address: | ||
| address: 127.0.0.1 | ||
| port_value: 8080 No newline at end of file |
|
latest render is here https://storage.googleapis.com/envoy-pr/1419c99/docs/intro/arch_overview/matching/matching_api.html not sure if its a tabs and spaces issue,, but some of the indents seem larger than others, which i think makes the config seem even more complicated in the complicated.yaml |
|
...actually its more in the simple.yaml i think |
|
@phlax good eye, thanks! Maybe a format linter for the YAML files would be a nice addition in the future |
Signed-off-by: Snow Pettersen <snowp@lyft.com>
ive added a ticket re general file linting ill look into yaml linting - i think it would be good to enforce least indent rules |
htuch
left a comment
There was a problem hiding this comment.
LGTM, will defer to @mattklein123 @phlax for their comments.
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
mattklein123
left a comment
There was a problem hiding this comment.
Very cool! LGTM with small comments.
/wait
| // To support configuring a :ref:`match tree <arch_overview_matching_api>`, use an | ||
| // :ref:`ExtensionWithMatcher <envoy_api_msg_extensions.common.matching.v3.ExtensionWithMatcher>` | ||
| // with the desired HTTP filter. |
There was a problem hiding this comment.
Can you wire up the new [#extension-category] stuff here? See other recent examples. I'm surprised this wasn't already done. cc @phlax
There was a problem hiding this comment.
I see this annotation is applied one layer higher. I would potentially move it here but up to you.
There was a problem hiding this comment.
im not following i dont see the extension-category
There was a problem hiding this comment.
There's // [#extension-category: envoy.filters.http] on L304 on the HttpFilter field declaration
| # Note this additional indirection; this is a workaround for Protobuf oneof limitations. | ||
| map: | ||
| some_value_to_match_on: # This is the header value we're trying to match against. | ||
| matcher: |
There was a problem hiding this comment.
This is really hard to read. Can you add more inline comments?
| intro/intro | ||
| listeners/listeners_toc | ||
| http/http | ||
| matching/matching |
There was a problem hiding this comment.
nit: I might consider moving this inside advanced? or at least lower in the list?
| the filter if `some-header: skip_filter` is present and `second-header` is set to *either* `foo` or | ||
| `bar`. | ||
|
|
||
| HTTP Filter Iteration Impact |
There was a problem hiding this comment.
Is it worth putting an attention block in here with a link to the open issue tracking match schema checking or similar?
| be performed based on incoming data. | ||
|
|
||
| The matching API is designed as a tree structure to allow for sublinear matching algorithms for | ||
| performance better than the linear list matching as seen in Envoy's HTTP routing. It makes heavy |
There was a problem hiding this comment.
s/performance better/better performance/
| When it comes to actions such as | ||
| :ref:`SkipFilter <envoy_v3_api_msg_extensions.filters.common.matcher.action.v3.SkipFilter>`, | ||
| this means that if the skip condition is based on anything but the request headers, the filter might | ||
| get partially applied, which might result in surprising beahvior. An example of this would be to |
|
current pages rendered: |
|
not sure exactly where the extension/categories should be but i think they are missing |
|
@snowp re-reading i think i understand - you can wrap any other extension using a matcher so no need to list out here i think i was a bit confused by where the extension category is currently pinned - i think it needs to be moved to the |
Signed-off-by: Snow Pettersen <snowp@lyft.com>
mattklein123
left a comment
There was a problem hiding this comment.
LGTM modulo @phlax other PR. Thanks!
phlax
left a comment
There was a problem hiding this comment.
lgtm - apologies for hesitation
|
@htuch Merging this is blocked on your review so please ptal :) |
htuch
left a comment
There was a problem hiding this comment.
Sorry, I LGTMed earlier but didn't approve.
|
@snowp needs main merge but otherwise good to go. |
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen snowp@lyft.com
Risk Level: n/a
Testing: n/a
Docs Changes: n/a
Release Notes: n/a
Platform Specific Features: n/a