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

On demand loading of ScopedRouteConfiguration #12640

Merged
merged 62 commits into from
Sep 9, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
ef08270
merge
Aug 7, 2020
c3d39db
add test and test migration to v3
Aug 10, 2020
7f93c95
add test and test migration to v3
Aug 10, 2020
88704aa
add unit test
Aug 10, 2020
71d9526
add unit test for dangling reference
Aug 11, 2020
1fb167f
add unit test for dangling reference
Aug 11, 2020
3cb0a1c
clean up
Aug 11, 2020
399ad9b
Merge branch 'master' of https://github.com/envoyproxy/envoy into laz…
Aug 11, 2020
2e5eccc
clean up
Aug 11, 2020
477dc6b
clean up
Aug 11, 2020
abd354b
test migration
Aug 12, 2020
25f487d
...
Aug 12, 2020
ab60437
finish
Aug 13, 2020
ae188bf
Merge branch 'master' of https://github.com/envoyproxy/envoy into tes…
Aug 13, 2020
7353474
clean up
Aug 13, 2020
3ce3677
make control flag bool
Aug 13, 2020
d54fc36
fix spelling
Aug 14, 2020
6588bf2
fix spelling
Aug 14, 2020
6cca147
clean up
Aug 14, 2020
f05c622
clean up
Aug 14, 2020
9626719
clean up
Aug 14, 2020
3f23c10
Merge branch 'master' of https://github.com/envoyproxy/envoy into laz…
Aug 15, 2020
b2e3e1f
change scope interface
Aug 15, 2020
2564425
...
Aug 15, 2020
7c4d74d
unit test for srds stats
Aug 17, 2020
8a641f2
refactor
Aug 17, 2020
c65f4b7
add comment
Aug 20, 2020
1aeb72b
sync
Aug 20, 2020
f941ea4
fix format
Aug 20, 2020
74f8c29
add comments
Aug 22, 2020
346ff81
fix spelling
Aug 22, 2020
a4153af
fix test
Aug 25, 2020
16aa77e
release note
Aug 25, 2020
44d5c29
release note
Aug 25, 2020
3dcfa02
release note
Aug 25, 2020
041bc98
release note
Aug 25, 2020
874e4d3
Merge branch 'master' of https://github.com/envoyproxy/envoy into laz…
Aug 25, 2020
67734d8
fix format
Aug 25, 2020
eddcd6d
add comment
Aug 26, 2020
8f40eb2
fix nullconfig comparasion
Aug 27, 2020
45e633c
clean up
Aug 27, 2020
d56f1bc
refactor
Aug 27, 2020
e08c201
Merge branch 'master' of https://github.com/envoyproxy/envoy into laz…
Aug 27, 2020
b9dc81f
pass scope key
Aug 27, 2020
71b7a1b
format
Aug 27, 2020
e4e7a51
add test
Aug 28, 2020
d9affce
clean up
Aug 31, 2020
896f52a
add test
Sep 1, 2020
826ef9d
test
Sep 2, 2020
e1e1e74
Merge branch 'master' of https://github.com/envoyproxy/envoy into laz…
Sep 2, 2020
44cb868
clean up
Sep 2, 2020
d8c3552
resolve conflict
Sep 2, 2020
62cb93f
less verbose
Sep 7, 2020
6d3f7f0
less verbose
Sep 7, 2020
d26f173
clean up
Sep 7, 2020
6a46ebb
clean up
Sep 7, 2020
d78d733
Merge branch 'master' of https://github.com/envoyproxy/envoy into laz…
Sep 7, 2020
70ec602
clean up
Sep 7, 2020
d60da44
clean up
Sep 7, 2020
ae7f157
fix missing test coverage
Sep 8, 2020
1da611e
add comment
Sep 8, 2020
f867e53
add comment
Sep 8, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
.. _config_http_filters_on_demand:

On-demand VHDS ans S/RDS Updates
On-demand VHDS and S/RDS Updates
================================

The on demand filter can be used to support either on demand VHDS or S/RDS update if configured in the filter chain.

The on-demand update filter can be used to request a :ref:`virtual host <envoy_v3_api_msg_config.route.v3.VirtualHost>`
htuch marked this conversation as resolved.
Show resolved Hide resolved
data if it's not already present in the :ref:`Route Configuration <envoy_v3_api_msg_config.route.v3.RouteConfiguration>`. The
contents of the *Host* or *:authority* header is used to create the on-demand request. For an on-demand
request to be created, :ref:`VHDS <envoy_v3_api_field_config.route.v3.RouteConfiguration.vhds>` must be enabled and either *Host*
or *:authority* header be present.

The on-demand update filter can also be used to request a :ref:`Route Configuration <envoy_v3_api_msg_config.route.v3.RouteConfiguration>`
data if RouteConfiguration is specified to be loaded on demand in the :ref:`Scoped RouteConfiguration <envoy_v3_api_msg_config.route.v3.ScopedRouteConfiguration>`. The
contents of the http header is used to find the scope and create the on-demand request.
The on-demand update filter can also be used to request a *Route Configuration* data if RouteConfiguration is specified to be
loaded on demand in the :ref:`Scoped RouteConfiguration <envoy_v3_api_msg_config.route.v3.ScopedRouteConfiguration>`.
The contents of the http header is used to find the scope and create the on-demand request.

On-demand VHDS and on-demand S/RDS can not be used at the same time at this point.
Copy link
Member

Choose a reason for hiding this comment

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

Do you have a tracking issue yet for converging the two?

Copy link
Member Author

Choose a reason for hiding this comment

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

I guess not.

Copy link
Member

Choose a reason for hiding this comment

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

Recommend adding one.


Expand Down
3 changes: 2 additions & 1 deletion docs/root/intro/arch_overview/http/http_routing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,11 @@ Route Scope
Scoped routing enables Envoy to put constraints on search space of domains and route rules.
A :ref:`Route Scope<envoy_api_msg_ScopedRouteConfiguration>` associates a key with a :ref:`route table <arch_overview_http_routing_route_table>`.
For each request, a scope key is computed dynamically by the HTTP connection manager to pick the :ref:`route table<envoy_api_msg_RouteConfiguration>`.
RouteConfiguration with scope can be loaded on demand with :ref:`v3 API reference <envoy_v3_api_msg_extensions.filters.http.on_demand.v3.OnDemand>` configured and on demand filed in protobuf set to true.
chaoqin-li1123 marked this conversation as resolved.
Show resolved Hide resolved

The Scoped RDS (SRDS) API contains a set of :ref:`Scopes <envoy_v3_api_msg_config.route.v3.ScopedRouteConfiguration>` resources, each defining independent routing configuration,
along with a :ref:`ScopeKeyBuilder <envoy_v3_api_msg_extensions.filters.network.http_connection_manager.v3.ScopedRoutes.ScopeKeyBuilder>`
defining the key construction algorithm used by Envoy to look up the scope corresponding to each request.
defining the key construction algorithm used by Envoy to look up the scope corresponding to each request.

For example, for the following scoped route configuration, Envoy will look into the "addr" header value, split the header value by ";" first, and use the first value for key 'x-foo-key' as the scope key.
If the "addr" header value is "foo=1;x-foo-key=127.0.0.1;x-bar-key=1.1.1.1", then "127.0.0.1" will be computed as the scope key to look up for corresponding route configuration.
Expand Down
3 changes: 2 additions & 1 deletion source/common/http/conn_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ void ConnectionManagerImpl::RdsRouteConfigUpdateRequester::requestRouteConfigUpd
} else if (parent_.snapped_scoped_routes_config_ != nullptr) {
Router::ScopeKeyPtr scope_key = parent_.snapped_scoped_routes_config_->computeScopeKey(
*parent_.filter_manager_.requestHeaders());
// If scope_key is not null, the scope exists but RouteConfiguration is not initialized.
if (scope_key != nullptr) {
// On demand srds
chaoqin-li1123 marked this conversation as resolved.
Show resolved Hide resolved
requestSrdsUpdate(std::move(scope_key), thread_local_dispatcher,
Expand All @@ -508,7 +509,7 @@ void ConnectionManagerImpl::RdsRouteConfigUpdateRequester::requestRouteConfigUpd
}

void ConnectionManagerImpl::RdsRouteConfigUpdateRequester::requestVhdsUpdate(
const std::string host_header, Event::Dispatcher& thread_local_dispatcher,
const std::string& host_header, Event::Dispatcher& thread_local_dispatcher,
Http::RouteConfigUpdatedCallbackSharedPtr route_config_updated_cb) {
route_config_provider_->requestVirtualHostsUpdate(host_header, thread_local_dispatcher,
std::move(route_config_updated_cb));
Expand Down
7 changes: 4 additions & 3 deletions source/common/http/conn_manager_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,17 @@ class ConnectionManagerImpl : Logger::Loggable<Logger::Id::http>,
ActiveStream& parent)
: route_config_provider_(route_config_provider), parent_(parent) {}

// Only on demand update for ScopeRdsConfigProvider is supported.
// InlineScopedRoutesConfigProvider will cast to nullptr in this ctor.
RdsRouteConfigUpdateRequester(Config::ConfigProvider* scoped_route_config_provider,
ActiveStream& parent)
// Only on demand update for ScopeRdsConfigProvider is supported.
// InlineScopedRoutesConfigProvider will cast to nullptr in this ctor.
: scoped_route_config_provider_(
dynamic_cast<Router::ScopedRdsConfigProvider*>(scoped_route_config_provider)),
parent_(parent) {}

void
requestRouteConfigUpdate(Http::RouteConfigUpdatedCallbackSharedPtr route_config_updated_cb);
void requestVhdsUpdate(const std::string host_header,
void requestVhdsUpdate(const std::string& host_header,
Event::Dispatcher& thread_local_dispatcher,
Http::RouteConfigUpdatedCallbackSharedPtr route_config_updated_cb);
void requestSrdsUpdate(Router::ScopeKeyPtr scope_key,
Expand Down
4 changes: 4 additions & 0 deletions source/common/router/scoped_rds.cc
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ void ScopedRdsConfigSubscription::RdsRouteConfigProviderHelper::maybeInitRdsConf
}

// Create a init_manager to create a rds provider.
// No transitive warming dependency here because only on demand update reach this point.
std::unique_ptr<Init::ManagerImpl> srds_init_mgr =
htuch marked this conversation as resolved.
Show resolved Hide resolved
std::make_unique<Init::ManagerImpl>(fmt::format("SRDS on demand init manager."));
std::unique_ptr<Cleanup> srds_initialization_continuation =
Expand Down Expand Up @@ -253,6 +254,9 @@ bool ScopedRdsConfigSubscription::addOrUpdateScopes(
scoped_route_info->scopeName(), version_info);
}

// scoped_route_info of both eager loading and on demand scope will be propagated to work
chaoqin-li1123 marked this conversation as resolved.
Show resolved Hide resolved
// threads. Upon a scoped RouteConfiguration miss, if the scope exists, an on demand update
// callback will be posted to main thread.
if (!updated_scopes.empty()) {
applyConfigUpdate([updated_scopes](ConfigProvider::ConfigConstSharedPtr config)
-> ConfigProvider::ConfigConstSharedPtr {
Expand Down
13 changes: 9 additions & 4 deletions test/common/router/scoped_rds_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1453,15 +1453,17 @@ on_demand: true
Stats::Gauge::ImportMode::Accumulate)
.value());
// All the on demand updated callbacks will be executed when the route table comes.
for (int i = 0; i < 5; i++) {
{
ScopeKeyPtr scope_key = getScopedRdsProvider()->config<ScopedConfigImpl>()->computeScopeKey(
TestRequestHeaderMapImpl{{"Addr", "x-foo-key;x-foo-key"}});
chaoqin-li1123 marked this conversation as resolved.
Show resolved Hide resolved
std::function<void(bool)> route_config_updated_cb = [](bool) {};
std::function<void(bool)> route_config_updated_cb = [](bool scope_exist) {
EXPECT_TRUE(scope_exist);
};
getScopedRdsProvider()->onDemandRdsUpdate(std::move(scope_key), event_dispatcher_,
std::move(route_config_updated_cb));
}
// After on demand request, push rds update, the callbacks will be executed.
EXPECT_CALL(event_dispatcher_, post(_)).Times(5);
EXPECT_CALL(event_dispatcher_, post(_)).Times(1);
chaoqin-li1123 marked this conversation as resolved.
Show resolved Hide resolved
pushRdsConfig({"foo_routes"}, "111");

ScopeKeyPtr scope_key = getScopedRdsProvider()->config<ScopedConfigImpl>()->computeScopeKey(
Expand All @@ -1473,7 +1475,10 @@ on_demand: true
Stats::Gauge::ImportMode::Accumulate)
.value());
EXPECT_CALL(event_dispatcher_, post(_)).Times(1);
chaoqin-li1123 marked this conversation as resolved.
Show resolved Hide resolved
std::function<void(bool)> route_config_updated_cb = [](bool) {};
// Scope no longer exists after srds update.
std::function<void(bool)> route_config_updated_cb = [](bool scope_exist) {
EXPECT_FALSE(scope_exist);
Copy link
Contributor

Choose a reason for hiding this comment

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

ditto here.

};
getScopedRdsProvider()->onDemandRdsUpdate(std::move(scope_key), event_dispatcher_,
chaoqin-li1123 marked this conversation as resolved.
Show resolved Hide resolved
std::move(route_config_updated_cb));
}
Expand Down
45 changes: 45 additions & 0 deletions test/integration/scoped_rds_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -732,5 +732,50 @@ on_demand: true
}
}

TEST_P(ScopedRdsIntegrationTest, OnDemandUpdateAfterActiveStreamDestroyed) {
config_helper_.addFilter(R"EOF(
name: envoy.filters.http.on_demand
)EOF");
const std::string scope_route1 = R"EOF(
name: foo_scope1
route_configuration_name: foo_route1
on_demand: true
key:
fragments:
- string_key: foo
)EOF";
on_server_init_function_ = [this, &scope_route1]() {
createScopedRdsStream();
sendSrdsResponse({scope_route1}, {scope_route1}, {}, "1");
};
initialize();
registerTestServerPorts({"http"});
fake_upstreams_[0]->set_allow_unexpected_disconnects(true);

const std::string route_config_tmpl = R"EOF(
name: {}
virtual_hosts:
- name: integration
domains: ["*"]
routes:
- match: {{ prefix: "/" }}
route: {{ cluster: {} }}
)EOF";
codec_client_ = makeHttpConnection(makeClientConnection((lookupPort("http"))));
// Request that match lazily loaded scope will trigger on demand loading.
chaoqin-li1123 marked this conversation as resolved.
Show resolved Hide resolved
auto response = codec_client_->makeHeaderOnlyRequest(
Http::TestRequestHeaderMapImpl{{":method", "GET"},
{":path", "/meh"},
{":authority", "host"},
{":scheme", "http"},
{"Addr", "x-foo-key=foo"}});
// Close the connection and destroy the active stream.
cleanupUpstreamAndDownstream();
// Push rds update and there is noexception thrown.
chaoqin-li1123 marked this conversation as resolved.
Show resolved Hide resolved
createRdsStream("foo_route1");
sendRdsResponse(fmt::format(route_config_tmpl, "foo_route1", "cluster_0"), "1");
test_server_->waitForCounterGe("http.config_test.rds.foo_route1.update_success", 1);
}

} // namespace
} // namespace Envoy