Skip to content

Commit c72de58

Browse files
committed
Pick VHDS virtual hosts over RDS ones when their names collide
1 parent ccb42a3 commit c72de58

2 files changed

Lines changed: 137 additions & 0 deletions

File tree

source/common/router/route_config_update_receiver_impl.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ void rebuildRouteConfigVirtualHosts(
2626
envoy::config::route::v3::RouteConfiguration& route_config) {
2727
route_config.clear_virtual_hosts();
2828
for (const auto& vhost : rds_vhosts) {
29+
auto found = vhds_vhosts.find(vhost.first);
30+
if (found != vhds_vhosts.end()) {
31+
continue;
32+
}
2933
route_config.mutable_virtual_hosts()->Add()->CheckTypeAndMergeFrom(vhost.second);
3034
}
3135
for (const auto& vhost : vhds_vhosts) {

test/common/router/vhds_test.cc

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,139 @@ name: my_route
316316
"vhost_vhds1" == actual_vhost_2.name());
317317
}
318318

319+
// verify that when RDS and VHDS define virtual hosts with the same name, VHDS takes precedence
320+
TEST_F(VhdsTest, VhdsOverridesRdsVirtualHostWithSameName) {
321+
const auto route_config =
322+
TestUtility::parseYaml<envoy::config::route::v3::RouteConfiguration>(R"EOF(
323+
name: my_route
324+
virtual_hosts:
325+
- name: overlapping_vhost
326+
domains: ["vhost.rds.domain"]
327+
routes:
328+
- match: { prefix: "/rds" }
329+
route: { cluster: rds_service }
330+
- name: vhost_rds_only
331+
domains: ["vhost.rds.only"]
332+
routes:
333+
- match: { prefix: "/rdsonly" }
334+
route: { cluster: rds_only_service }
335+
vhds:
336+
config_source:
337+
api_config_source:
338+
api_type: DELTA_GRPC
339+
grpc_services:
340+
envoy_grpc:
341+
cluster_name: xds_cluster
342+
)EOF");
343+
RouteConfigUpdatePtr config_update_info = makeRouteConfigUpdate(route_config);
344+
345+
VhdsSubscriptionPtr subscription = VhdsSubscription::createVhdsSubscription(
346+
config_update_info, factory_context_, context_, provider_)
347+
.value();
348+
EXPECT_EQ(2UL, config_update_info->protobufConfigurationCast().virtual_hosts_size());
349+
350+
// Add a VHDS virtual host with the same name as one of the RDS virtual hosts
351+
auto vhost = buildVirtualHost("overlapping_vhost", "vhost.vhds.domain");
352+
const auto& added_resources = buildAddedResources({vhost});
353+
const auto decoded_resources =
354+
TestUtility::decodeResources<envoy::config::route::v3::VirtualHost>(added_resources);
355+
const Protobuf::RepeatedPtrField<std::string> removed_resources;
356+
EXPECT_TRUE(factory_context_.cluster_manager_.subscription_factory_.callbacks_
357+
->onConfigUpdate(decoded_resources.refvec_, removed_resources, "1")
358+
.ok());
359+
360+
// Should have 2 virtual hosts: vhost_rds_only from RDS + overlapping_vhost from VHDS
361+
EXPECT_EQ(2UL, config_update_info->protobufConfigurationCast().virtual_hosts_size());
362+
363+
// Verify the VHDS version of the overlapping vhost is used (with vhds domain, not rds domain)
364+
bool found_vhds_version = false;
365+
bool found_rds_only = false;
366+
for (int i = 0; i < config_update_info->protobufConfigurationCast().virtual_hosts_size(); ++i) {
367+
const auto& vh = config_update_info->protobufConfigurationCast().virtual_hosts(i);
368+
if (vh.name() == "overlapping_vhost") {
369+
// The VHDS version should have "vhost.vhds.domain", not "vhost.rds.domain"
370+
EXPECT_EQ("vhost.vhds.domain", vh.domains(0));
371+
found_vhds_version = true;
372+
} else if (vh.name() == "vhost_rds_only") {
373+
found_rds_only = true;
374+
}
375+
}
376+
EXPECT_TRUE(found_vhds_version);
377+
EXPECT_TRUE(found_rds_only);
378+
}
379+
380+
// verify VHDS precedence is maintained after an RDS update
381+
TEST_F(VhdsTest, VhdsOverridesRdsVirtualHostAfterRdsUpdate) {
382+
const auto route_config =
383+
TestUtility::parseYaml<envoy::config::route::v3::RouteConfiguration>(R"EOF(
384+
name: my_route
385+
virtual_hosts:
386+
- name: overlapping_vhost
387+
domains: ["vhost.rds.domain"]
388+
routes:
389+
- match: { prefix: "/rds" }
390+
route: { cluster: rds_service }
391+
vhds:
392+
config_source:
393+
api_config_source:
394+
api_type: DELTA_GRPC
395+
grpc_services:
396+
envoy_grpc:
397+
cluster_name: xds_cluster
398+
)EOF");
399+
RouteConfigUpdatePtr config_update_info = makeRouteConfigUpdate(route_config);
400+
401+
VhdsSubscriptionPtr subscription = VhdsSubscription::createVhdsSubscription(
402+
config_update_info, factory_context_, context_, provider_)
403+
.value();
404+
405+
// Add a VHDS virtual host with the same name
406+
auto vhost = buildVirtualHost("overlapping_vhost", "vhost.vhds.domain");
407+
const auto& added_resources = buildAddedResources({vhost});
408+
const auto decoded_resources =
409+
TestUtility::decodeResources<envoy::config::route::v3::VirtualHost>(added_resources);
410+
const Protobuf::RepeatedPtrField<std::string> removed_resources;
411+
EXPECT_TRUE(factory_context_.cluster_manager_.subscription_factory_.callbacks_
412+
->onConfigUpdate(decoded_resources.refvec_, removed_resources, "1")
413+
.ok());
414+
415+
// Now trigger an RDS update that still has the same-named vhost
416+
const auto updated_route_config =
417+
TestUtility::parseYaml<envoy::config::route::v3::RouteConfiguration>(R"EOF(
418+
name: my_route
419+
virtual_hosts:
420+
- name: overlapping_vhost
421+
domains: ["vhost.rds.updated"]
422+
routes:
423+
- match: { prefix: "/rds-updated" }
424+
route: { cluster: rds_updated_service }
425+
- name: vhost_rds_new
426+
domains: ["vhost.rds.new"]
427+
routes:
428+
- match: { prefix: "/rdsnew" }
429+
route: { cluster: rds_new_service }
430+
vhds:
431+
config_source:
432+
api_config_source:
433+
api_type: DELTA_GRPC
434+
grpc_services:
435+
envoy_grpc:
436+
cluster_name: xds_cluster
437+
)EOF");
438+
config_update_info->onRdsUpdate(updated_route_config, "2");
439+
440+
// Should have 2: vhost_rds_new from RDS + overlapping_vhost from VHDS
441+
EXPECT_EQ(2UL, config_update_info->protobufConfigurationCast().virtual_hosts_size());
442+
443+
// Verify VHDS version still takes precedence after RDS update
444+
for (int i = 0; i < config_update_info->protobufConfigurationCast().virtual_hosts_size(); ++i) {
445+
const auto& vh = config_update_info->protobufConfigurationCast().virtual_hosts(i);
446+
if (vh.name() == "overlapping_vhost") {
447+
EXPECT_EQ("vhost.vhds.domain", vh.domains(0));
448+
}
449+
}
450+
}
451+
319452
} // namespace
320453
} // namespace Router
321454
} // namespace Envoy

0 commit comments

Comments
 (0)