Skip to content

docs: document HTTP generic matching#14864

Merged
mattklein123 merged 16 commits intoenvoyproxy:mainfrom
snowp:matching-docs
Mar 19, 2021
Merged

docs: document HTTP generic matching#14864
mattklein123 merged 16 commits intoenvoyproxy:mainfrom
snowp:matching-docs

Conversation

@snowp
Copy link
Copy Markdown
Contributor

@snowp snowp commented Jan 29, 2021

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

Signed-off-by: Snow Pettersen <snowp@lyft.com>
@repokitteh-read-only
Copy link
Copy Markdown

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to api/envoy/.
API shepherd assignee is @htuch
CC @envoyproxy/api-watchers: FYI only for changes made to api/envoy/.

🐱

Caused by: #14864 was opened by snowp.

see: more, trace.

Copy link
Copy Markdown
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@phlax should this be a verified code example? Can we generally just enable this for all new code fragments?

Copy link
Copy Markdown
Member

@phlax phlax Jan 31, 2021

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

its kinda the other way round in a sense

if you separate the config it will automatically get validated unless its specifically excluded

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

...at least for the envoy config - not sure about any yaml validation

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nit: prefer some RST formatting for filer proper names, e.g. *SetResponseCode*.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Surprises are fun :) Is there a way to call out some concrete examples of where this happens?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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

Snow Pettersen added 5 commits February 1, 2021 19:55
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>
Snow Pettersen added 3 commits March 2, 2021 18:37
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
Copy link
Copy Markdown
Contributor Author

snowp commented Mar 9, 2021

This should be ready for another pass @htuch

Copy link
Copy Markdown
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

@snowp thanks, generally looks great, just a few comments.
/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 for all filter callbacks (e.g. encodeHeaders, encodeData,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
// 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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

RST link to ExtensionMatcher def

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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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:

  1. 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.
  2. 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).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
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

Snow Pettersen added 2 commits March 11, 2021 15:24
Signed-off-by: Snow Pettersen <snowp@lyft.com>
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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

also new line here

@phlax
Copy link
Copy Markdown
Member

phlax commented Mar 11, 2021

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

@phlax
Copy link
Copy Markdown
Member

phlax commented Mar 11, 2021

...actually its more in the simple.yaml i think

@snowp
Copy link
Copy Markdown
Contributor Author

snowp commented Mar 11, 2021

@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>
@phlax
Copy link
Copy Markdown
Member

phlax commented Mar 11, 2021

Maybe a format linter for the YAML files would be a nice addition in the future

ive added a ticket re general file linting

#15442

ill look into yaml linting - i think it would be good to enforce least indent rules

Copy link
Copy Markdown
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

LGTM, will defer to @mattklein123 @phlax for their comments.

Snow Pettersen added 2 commits March 12, 2021 12:24
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Signed-off-by: Snow Pettersen <snowp@lyft.com>
Copy link
Copy Markdown
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.

Very cool! LGTM with small comments.

/wait

Comment on lines +887 to +889
// 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.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you wire up the new [#extension-category] stuff here? See other recent examples. I'm surprised this wasn't already done. cc @phlax

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I see this annotation is applied one layer higher. I would potentially move it here but up to you.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

im not following i dont see the extension-category

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is really hard to read. Can you add more inline comments?

intro/intro
listeners/listeners_toc
http/http
matching/matching
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

s/beahviour/behaviour/

@phlax
Copy link
Copy Markdown
Member

phlax commented Mar 15, 2021

not sure exactly where the extension/categories should be but i think they are missing

@phlax
Copy link
Copy Markdown
Member

phlax commented Mar 18, 2021

@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 typed_config - but that is unrelated to this PR

Signed-off-by: Snow Pettersen <snowp@lyft.com>
mattklein123
mattklein123 previously approved these changes Mar 18, 2021
Copy link
Copy Markdown
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.

LGTM modulo @phlax other PR. Thanks!

phlax
phlax previously approved these changes Mar 18, 2021
Copy link
Copy Markdown
Member

@phlax phlax left a comment

Choose a reason for hiding this comment

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

lgtm - apologies for hesitation

@snowp
Copy link
Copy Markdown
Contributor Author

snowp commented Mar 18, 2021

@htuch Merging this is blocked on your review so please ptal :)

htuch
htuch previously approved these changes Mar 19, 2021
Copy link
Copy Markdown
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

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

Sorry, I LGTMed earlier but didn't approve.

@htuch
Copy link
Copy Markdown
Member

htuch commented Mar 19, 2021

@snowp needs main merge but otherwise good to go.

Signed-off-by: Snow Pettersen <snowp@lyft.com>
@snowp snowp dismissed stale reviews from htuch, phlax, and mattklein123 via 38ff269 March 19, 2021 12:37
@mattklein123 mattklein123 merged commit b3fb91f into envoyproxy:main Mar 19, 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.

4 participants