dynamic_modules: support per route config#39348
Conversation
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
|
CC @envoyproxy/api-shepherds: Your approval is needed for changes made to |
|
/coverage |
|
Coverage for this Pull Request will be rendered here: https://storage.googleapis.com/envoy-pr/39348/coverage/index.html The coverage results are (re-)rendered each time the CI |
mathetake
left a comment
There was a problem hiding this comment.
Do you really need this? disabled API of HTTP filter can be used to achieve per route configuration without specific API in each HTTP filter.
E.g. https://github.com/envoyproxy/dynamic-modules-examples/compare/perroute?expand=1 this should be enough to achieve everything in this PR if i am not missing something else
/wait
/wait
|
If I understand the suggested approach correctly - you will need a unique filter in the listener filter chain for each unique per-route config. while technically possible, it has issues - making control plane & data plane more complex. With this approach only one filter is needed in the filter chain. |
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
Could you elaborate on how? This PR is not needed so definitely data plane is not more complex than with this IMO. I believe this is introduced by @wbpcode to eliminate the need to have per-route API for every single one of extension, notably the need for PRs like this. cc @arkodg I believe this is how Envoy Gateway handles with per-route settings. |
|
With the approach you are suggesting, will i be able to use one filter on the HCM filter chain, and multiple different configs on the route? I believe the answer is no, please correct me if this is not the case. Is envoy getting rid of per-filter config for other http filters? |
|
thank you for elaborating, and I think i am getting to understand the "complexity" in the control plane you meant. However, I believe this should be resolved at more fundamental level without introducing per-route config for each existing extension. could you give me some time to find other approach ? |
|
Just my two cents: The current per-route configuration of each HTTP filter feels quite messy. There’s duplication at two levels, and the approaches are inconsistent — some filters duplicate all configurations at the route level, others only duplicate parts, and some introduce entirely different configurations. Setting up multi-filters on the LDS and simply enabling the necessary ones on the RDS seems like a much cleaner and more consistent solution to me. |
While I understand your perspective, I still prefer to use the per route config mechanism. Given that this PR doesn't impede you from using your approach, what's the harm in merging it? |
|
I personally think this make sense. Actually, type_per_filter_config is still the main way to enable different behavior of same filter in different routes. |
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
c7f8da7 to
996a05d
Compare
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
b29e656 to
6f557a3
Compare
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
mathetake
left a comment
There was a problem hiding this comment.
sorry for the delay (was on ooo for a few days). almost there but left a high level comment!
| // The name for this filter configuration. This can be used to distinguish between different filter implementations | ||
| // inside a dynamic module. For example, a module can have completely different filter implementations. | ||
| // When Envoy receives this configuration, it passes the filter_name to the dynamic module's HTTP per-route filter config init function | ||
| // together with the filter_config. | ||
| // That way a module can decide which in-module filter implementation to use based on the name at load time. | ||
| string filter_name = 2; |
There was a problem hiding this comment.
i think this is in reality not a filter but a filter_configuration. That is, the name here is nothing to do with the filter_name on the referencing HTTP filter side configuration. At least i would like to call this filter_config_name or per_route_config_name to differentiate these two since otherwise, this feels like these two are somehow associated. In fact, at the higher level on SDK, this will passed to NewHttpFilterPerRouteConfigFunction which matches the name i suggested.
| // The name for this filter configuration. This can be used to distinguish between different filter implementations | |
| // inside a dynamic module. For example, a module can have completely different filter implementations. | |
| // When Envoy receives this configuration, it passes the filter_name to the dynamic module's HTTP per-route filter config init function | |
| // together with the filter_config. | |
| // That way a module can decide which in-module filter implementation to use based on the name at load time. | |
| string filter_name = 2; | |
| // The name for this per-route configuration. This can be used to distinguish between different per-route config implementations | |
| // inside a dynamic module. For example, a module can have completely different implementations. | |
| // When Envoy receives this configuration, it passes the filter_name to the dynamic module's HTTP per-route filter config init function | |
| // together with the filter_config. | |
| // That way a module can decide which in-module filter implementation to use based on the name at load time. | |
| string per_route_config_name = 2; |
or maybe we might want to move NewHttpFilterPerRouteConfigFunction into a part of HttpFilterConfig trait and use the name here to point to that to clarify these relationship.
There was a problem hiding this comment.
Usually the way we do these filters, is that the same filter does both the listener level config, and route level config. so it's helpful to have access to the filter_name when creating a route level config (and have it be the same name as the listener level config).
That's why i think the filter_name is appropriate here. That said, if you feel strongly about this change, I ok making it. LMK what you think!
There was a problem hiding this comment.
yeah what i meant was that this filter_name can be arbitrary regardless of where it is used. For example
diff --git a/test/extensions/dynamic_modules/http/integration_test.cc b/test/extensions/dynamic_modules/http/integration_test.cc
index 476ec00cf1..b74c9c400a 100644
--- a/test/extensions/dynamic_modules/http/integration_test.cc
+++ b/test/extensions/dynamic_modules/http/integration_test.cc
@@ -45,7 +45,7 @@ filter_config:
envoy::extensions::filters::http::dynamic_modules::v3::DynamicModuleFilterPerRoute
per_route_config_proto;
TestUtility::loadFromYaml(
- fmt::format(filter_per_route_config, filter_name, type_url, per_route_config),
+ fmt::format(filter_per_route_config, "anything", type_url, per_route_config),
per_route_config_proto);
config_helper_.addConfigModifier(
diff --git a/test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs b/test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs
index b7ff963ee8..1de6bef25e 100644
--- a/test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs
+++ b/test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs
@@ -38,7 +38,7 @@ fn new_http_filter_config_fn<EC: EnvoyHttpFilterConfig, EHF: EnvoyHttpFilter>(
fn new_http_filter_per_route_config_fn(name: &str, config: &[u8]) -> Option<Box<dyn Any>> {
match name {
- "per_route_config" => Some(Box::new(PerRoutePerRouteFilterConfig {
+ "anything" => Some(Box::new(PerRoutePerRouteFilterConfig {
value: String::from_utf8(config.to_owned()).unwrap(),
})),
_ => panic!("Unknown filter name: {}", name),this can also pass the integration test here where this "filter_name" ("anything") is irrelevant to the actual HCM dynamic modules http filter's filter_name ("per_route_config"). I wondered if there's any better way to somehow associate "filter_name" here with the listener level one if we use it here as well or I would prefer to rename it to per_route_config_name.
There was a problem hiding this comment.
I'm not aware of way to associate these in envoy. i can rename to per_route_config_name
There was a problem hiding this comment.
on second thought, i think i am good with the original filter_name at the end of the day. i am sorry about the round trip but could you revert the rename change to filter_name f804884 ? 🙇
after that i will approve this 🙏
There was a problem hiding this comment.
kindly ping @yuval-k in case you missed my comment ^ 👍
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
|
check failes on |
|
/retest another flake :/ |
|
/retest |
mathetake
left a comment
There was a problem hiding this comment.
thank you! looks good to me so far modulo the API naming as per the comment.
i would like an input from @mattklein123 regarding the API as well as the Rust SDK side, especially around the use of Any/Arc etc.
/wait
| // The name for this filter configuration. This can be used to distinguish between different filter implementations | ||
| // inside a dynamic module. For example, a module can have completely different filter implementations. | ||
| // When Envoy receives this configuration, it passes the filter_name to the dynamic module's HTTP per-route filter config init function | ||
| // together with the filter_config. | ||
| // That way a module can decide which in-module filter implementation to use based on the name at load time. | ||
| string filter_name = 2; |
There was a problem hiding this comment.
yeah what i meant was that this filter_name can be arbitrary regardless of where it is used. For example
diff --git a/test/extensions/dynamic_modules/http/integration_test.cc b/test/extensions/dynamic_modules/http/integration_test.cc
index 476ec00cf1..b74c9c400a 100644
--- a/test/extensions/dynamic_modules/http/integration_test.cc
+++ b/test/extensions/dynamic_modules/http/integration_test.cc
@@ -45,7 +45,7 @@ filter_config:
envoy::extensions::filters::http::dynamic_modules::v3::DynamicModuleFilterPerRoute
per_route_config_proto;
TestUtility::loadFromYaml(
- fmt::format(filter_per_route_config, filter_name, type_url, per_route_config),
+ fmt::format(filter_per_route_config, "anything", type_url, per_route_config),
per_route_config_proto);
config_helper_.addConfigModifier(
diff --git a/test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs b/test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs
index b7ff963ee8..1de6bef25e 100644
--- a/test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs
+++ b/test/extensions/dynamic_modules/test_data/rust/http_integration_test.rs
@@ -38,7 +38,7 @@ fn new_http_filter_config_fn<EC: EnvoyHttpFilterConfig, EHF: EnvoyHttpFilter>(
fn new_http_filter_per_route_config_fn(name: &str, config: &[u8]) -> Option<Box<dyn Any>> {
match name {
- "per_route_config" => Some(Box::new(PerRoutePerRouteFilterConfig {
+ "anything" => Some(Box::new(PerRoutePerRouteFilterConfig {
value: String::from_utf8(config.to_owned()).unwrap(),
})),
_ => panic!("Unknown filter name: {}", name),this can also pass the integration test here where this "filter_name" ("anything") is irrelevant to the actual HCM dynamic modules http filter's filter_name ("per_route_config"). I wondered if there's any better way to somehow associate "filter_name" here with the listener level one if we use it here as well or I would prefer to rename it to per_route_config_name.
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
|
tsan flake /reset |
|
/retest |
|
hi @mathetake @mattklein123, friendly ping on this. Happy to address any additional feedback! |
mathetake
left a comment
There was a problem hiding this comment.
Thanks, could you add a unit test where the Arc reference is actually working as intended in filter_test.cc? like the case where:
- write a filter that retrieves the per_route config in on_request_header and save it in a filter instance, and invoke the event hook
- release the per-route config on the host side so that Envoy side memory is released as well as envoy_dynamic_module_on_http_filter_per_route_config_destroy is called.
- Invoke on_response_header and try to access the arc wrapped memory region
i think if the arc is not working as we intended the test should crash or TSAN should detect the memory leak in that case. just in case!
Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
|
hi @mathetake! just pushed a unit tests as you suggested |
|
flake: |
|
/retest |
Co-authored-by: Takeshi Yoneda <t.y.mathetake@gmail.com> Signed-off-by: Yuval Kohavi <yuval.kohavi@gmail.com>
|
hi @abeyad ! friendly ping if you are able to review this? |
Commit Message: Support per route filter configuration in dynamic modules
Risk Level: Low. New functionality. existing functionality should not be impacted.
Testing: Updated unit & integration test
Release Notes:
dynamic_modules now support per route filter config