router: support dynamic host metadata headers#2179
router: support dynamic host metadata headers#2179zuercher merged 17 commits intoenvoyproxy:masterfrom
Conversation
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
|
I wanted to update test/integration/header_integration_test.cc to test these, but it seems pretty tricky to use the existing config modifiers to set up an EDS cluster (which is required to get endpoint metadata). Am I missing something? |
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
For an integration test, you would need to also setup a fake EDS server. Harvey did a bunch of work to get an ADS integration test working: https://github.com/envoyproxy/envoy/blob/master/test/integration/ads_integration_test.cc. If you want to do an integration test you could build on that and it would probably be pretty straightforward. |
| namespace { | ||
|
|
||
| // Parse list of namespace and keys into a vector. Supports backslash escaping. | ||
| std::vector<std::string> parseUpstreamMetadataParams(const std::string& field) { |
There was a problem hiding this comment.
Before doing a full review we should consider @htuch comment in the data-plane-api PR as to whether we potentially want to use embedded JSON here or something so we could use the JSON parser. Seems like a good idea to me to use JSON perhaps, but I could go either way. Thoughts?
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
|
@zuercher can you look at TSAN? I can take a look after that is fixed. |
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
|
For reference, the TSAN error occurs when some field descriptor in the DiscoveryRequest hasn't been fully initialized -- the protobuf lib initializes it using what looks to be an atomicity-based mutex-free algorithm, but apparently TSAN doesn't like it. I believe the offending address is the atomically-accessed guard field. In any event, my fix is to initialize the field descriptors by parsing the message from YAML, which is probably easier to read than the C++ API version I had before. |
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
mattklein123
left a comment
There was a problem hiding this comment.
Great stuff. Few small comments. @alyssawilk do you mind taking a look at the test stuff? Might be best for your other change to merge if we are going to do other base test changes.
| return request_info.getDownstreamAddress(); | ||
| }; | ||
| } else if (StringUtil::startsWith(field_name.c_str(), "UPSTREAM_METADATA")) { | ||
| field_extractor_ = parseUpstreamMetadataField(field_name.substr(17)); |
There was a problem hiding this comment.
nit: Might use sizeof() here or some other constant to avoid the magic '17'
| "Invalid value.\n"); | ||
|
|
||
| // No parameters. | ||
| EXPECT_THROW(RequestInfoHeaderFormatter requestInfoHeaderFormatter("UPSTREAM_METADATA", false), |
There was a problem hiding this comment.
Is it possible to use EXPECT_THROW_WITH_MESSAGE for all of these?
| )EOF")); | ||
|
|
||
| // Give the config utility a place to stuff the upstream host's port (must come before | ||
| // the eds-cluster to keep the upstreams and ports in the same order).) |
| EXPECT_EQ(expected_headers, headers); | ||
| } | ||
|
|
||
| bool use_eds_{0}; |
There was a problem hiding this comment.
nit: I would use '{}' or '{false}' here vs. 0
| api_type: GRPC | ||
| )EOF")); | ||
|
|
||
| // Give the config utility a place to stuff the upstream host's port (must come before |
There was a problem hiding this comment.
This is a little confusing. Is this just because of how the default config stuff works? Would it be worth it to build this EDS stuff into the base integration class? It seems generally useful and very cool. cc @alyssawilk
There was a problem hiding this comment.
Yeah, I think the same way that we special cased the HttpConnectionManager it'd be useful to have utilities to play with EDS config directly.
There was a problem hiding this comment.
I can take a look at making the config smarter about EDS in another review, if you'd like.
There was a problem hiding this comment.
If you want to do a follow up / TODO that's fine, but can you add more of a comment here? It's confusing why the placeholder is necessary.
There was a problem hiding this comment.
But yes, it's to do with ConfigHelper expecting the number of ports assigned to match the number of upstreams during the call to finalize.
|
|
||
| std::function<std::string(const Envoy::AccessLog::RequestInfo&)> | ||
| parseUpstreamMetadataField(const std::string& params_str) { | ||
| if (params_str.empty() || params_str[0] != '(' || params_str[params_str.size() - 1] != ')') { |
There was a problem hiding this comment.
if (params_str.empty() || params_str.front() != '(' || params_str.back() != ')')
| return [params](const Envoy::AccessLog::RequestInfo& request_info) -> std::string { | ||
| Upstream::HostDescriptionConstSharedPtr host = request_info.upstreamHost(); | ||
| if (!host) { | ||
| return ""; |
There was a problem hiding this comment.
I slightly prefer "return std::string()" (same for other places in this function)
| } | ||
|
|
||
| std::function<std::string(const Envoy::AccessLog::RequestInfo&)> | ||
| parseUpstreamMetadataField(const std::string& params_str) { |
There was a problem hiding this comment.
Can you add a comment with an example string of the correct format near the top of the function, so I can quickly see visually what it is this function is parsing?
| return value->bool_value() ? "true" : "false"; | ||
|
|
||
| default: | ||
| // Unsupported type or null value. |
There was a problem hiding this comment.
This case will be hard for a user to debug. Since we found something, but it's the wrong type, would it be better to return "unsupported metadata type" or something, or perhaps log something?
There was a problem hiding this comment.
I think returning an arbitrary string would be bad. I've added a log message.
There was a problem hiding this comment.
IMO debug is a more appropriate log level here, as this could emit at high rate due to external factors.
There was a problem hiding this comment.
Dumb story, but yes, that's what I forgot to change it back to before committing.
| return request_info.getDownstreamAddress(); | ||
| }; | ||
| } else if (StringUtil::startsWith(field_name.c_str(), "UPSTREAM_METADATA")) { | ||
| field_extractor_ = parseUpstreamMetadataField(field_name.substr(17)); |
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
Signed-off-by: Stephan Zuercher <stephan@turbinelabs.io>
* update envoy sha * fix build
Modifies the
Router::RequestInfoHeaderFormatterto support extracting string, numeric, and boolean values from the upstream host provided byAccessLog::RequestInfo.Modifies
Router::HeaderParserto omit headers whose formatted value is an empty string.Risk Level: Low
Testing:
Unit tests to cover parsing of new header variable expression.
Docs Changes:
envoyproxy/data-plane-api#335
Release Notes:
Updated RAW_RELEASE_NOTES.md
Fixes #2148.