From 128acb58c3292299edb4672c6c6baad9d10e62e9 Mon Sep 17 00:00:00 2001 From: Fred Douglas <43351173+fredlas@users.noreply.github.com> Date: Tue, 13 Aug 2019 16:12:36 -0700 Subject: [PATCH] config: WatchMap: cleaner management of watches (#7108) To be used with delta ADS. Could probably be used with the current GrpcMuxImpl. Has the SubscriptionCallbacks interface, so a GrpcMux can just directly pass onConfigUpdate() calls through to the WatchMap, which will then appropriately distribute the various resources to the various watches' SubscriptionCallbacks. #4991 Risk Level: none, not yet built into Envoy Testing: unit tests for the new class Signed-off-by: Fred Douglas --- include/envoy/config/BUILD | 8 + include/envoy/config/grpc_mux.h | 1 + source/common/config/BUILD | 102 ++++--- source/common/config/watch_map.cc | 170 ++++++++++++ source/common/config/watch_map.h | 115 ++++++++ source/docs/xDS_code_diagram.png | Bin 0 -> 97291 bytes test/common/config/BUILD | 11 + test/common/config/watch_map_test.cc | 397 +++++++++++++++++++++++++++ tools/spelling_dictionary.txt | 3 + 9 files changed, 762 insertions(+), 45 deletions(-) create mode 100644 source/common/config/watch_map.cc create mode 100644 source/common/config/watch_map.h create mode 100644 source/docs/xDS_code_diagram.png create mode 100644 test/common/config/watch_map_test.cc diff --git a/include/envoy/config/BUILD b/include/envoy/config/BUILD index 2b2504620c99..001d3cbe46af 100644 --- a/include/envoy/config/BUILD +++ b/include/envoy/config/BUILD @@ -66,6 +66,14 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "watch_map_interface", + hdrs = ["watch_map.h"], + deps = [ + ":subscription_interface", + ], +) + envoy_cc_library( name = "xds_grpc_context_interface", hdrs = ["xds_grpc_context.h"], diff --git a/include/envoy/config/grpc_mux.h b/include/envoy/config/grpc_mux.h index 4888e4e7e716..1d9920e2d5e3 100644 --- a/include/envoy/config/grpc_mux.h +++ b/include/envoy/config/grpc_mux.h @@ -25,6 +25,7 @@ struct ControlPlaneStats { ALL_CONTROL_PLANE_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT) }; +// TODO(fredlas) redundant to SubscriptionCallbacks; remove this one. class GrpcMuxCallbacks { public: virtual ~GrpcMuxCallbacks() = default; diff --git a/source/common/config/BUILD b/source/common/config/BUILD index 378512d4df5f..f3bcaacfdbb7 100644 --- a/source/common/config/BUILD +++ b/source/common/config/BUILD @@ -32,18 +32,20 @@ envoy_cc_library( ) envoy_cc_library( - name = "filesystem_subscription_lib", - srcs = ["filesystem_subscription_impl.cc"], - hdrs = ["filesystem_subscription_impl.h"], + name = "config_provider_lib", + srcs = ["config_provider_impl.cc"], + hdrs = ["config_provider_impl.h"], deps = [ - "//include/envoy/config:subscription_interface", - "//include/envoy/event:dispatcher_interface", - "//include/envoy/filesystem:filesystem_interface", - "//source/common/common:minimal_logger_lib", - "//source/common/config:utility_lib", + ":utility_lib", + "//include/envoy/config:config_provider_interface", + "//include/envoy/config:config_provider_manager_interface", + "//include/envoy/init:manager_interface", + "//include/envoy/server:admin_interface", + "//include/envoy/server:config_tracker_interface", + "//include/envoy/singleton:instance_interface", + "//include/envoy/thread_local:thread_local_interface", + "//source/common/init:target_lib", "//source/common/protobuf", - "//source/common/protobuf:message_validator_lib", - "//source/common/protobuf:utility_lib", ], ) @@ -100,6 +102,22 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "filesystem_subscription_lib", + srcs = ["filesystem_subscription_impl.cc"], + hdrs = ["filesystem_subscription_impl.h"], + deps = [ + "//include/envoy/config:subscription_interface", + "//include/envoy/event:dispatcher_interface", + "//include/envoy/filesystem:filesystem_interface", + "//source/common/common:minimal_logger_lib", + "//source/common/config:utility_lib", + "//source/common/protobuf", + "//source/common/protobuf:message_validator_lib", + "//source/common/protobuf:utility_lib", + ], +) + envoy_cc_library( name = "grpc_stream_lib", hdrs = ["grpc_stream.h"], @@ -265,12 +283,6 @@ envoy_cc_library( ], ) -envoy_cc_library( - name = "resources_lib", - hdrs = ["resources.h"], - deps = ["//source/common/singleton:const_singleton"], -) - envoy_cc_library( name = "rds_json_lib", srcs = ["rds_json.cc"], @@ -288,6 +300,25 @@ envoy_cc_library( ], ) +envoy_cc_library( + name = "resources_lib", + hdrs = ["resources.h"], + deps = ["//source/common/singleton:const_singleton"], +) + +envoy_cc_library( + name = "remote_data_fetcher_lib", + srcs = ["remote_data_fetcher.cc"], + hdrs = ["remote_data_fetcher.h"], + deps = [ + "//include/envoy/upstream:cluster_manager_interface", + "//source/common/common:hex_lib", + "//source/common/crypto:utility_lib", + "//source/common/http:utility_lib", + "@envoy_api//envoy/api/v2/core:http_uri_cc", + ], +) + envoy_cc_library( name = "runtime_utility_lib", srcs = ["runtime_utility.cc"], @@ -361,42 +392,23 @@ envoy_cc_library( ) envoy_cc_library( - name = "well_known_names", - srcs = ["well_known_names.cc"], - hdrs = ["well_known_names.h"], + name = "watch_map_lib", + srcs = ["watch_map.cc"], + hdrs = ["watch_map.h"], deps = [ + "//include/envoy/config:subscription_interface", "//source/common/common:assert_lib", - "//source/common/singleton:const_singleton", - ], -) - -envoy_cc_library( - name = "config_provider_lib", - srcs = ["config_provider_impl.cc"], - hdrs = ["config_provider_impl.h"], - deps = [ - ":utility_lib", - "//include/envoy/config:config_provider_interface", - "//include/envoy/config:config_provider_manager_interface", - "//include/envoy/init:manager_interface", - "//include/envoy/server:admin_interface", - "//include/envoy/server:config_tracker_interface", - "//include/envoy/singleton:instance_interface", - "//include/envoy/thread_local:thread_local_interface", - "//source/common/init:target_lib", + "//source/common/common:minimal_logger_lib", "//source/common/protobuf", ], ) envoy_cc_library( - name = "remote_data_fetcher_lib", - srcs = ["remote_data_fetcher.cc"], - hdrs = ["remote_data_fetcher.h"], + name = "well_known_names", + srcs = ["well_known_names.cc"], + hdrs = ["well_known_names.h"], deps = [ - "//include/envoy/upstream:cluster_manager_interface", - "//source/common/common:hex_lib", - "//source/common/crypto:utility_lib", - "//source/common/http:utility_lib", - "@envoy_api//envoy/api/v2/core:http_uri_cc", + "//source/common/common:assert_lib", + "//source/common/singleton:const_singleton", ], ) diff --git a/source/common/config/watch_map.cc b/source/common/config/watch_map.cc new file mode 100644 index 000000000000..718231009101 --- /dev/null +++ b/source/common/config/watch_map.cc @@ -0,0 +1,170 @@ +#include "common/config/watch_map.h" + +namespace Envoy { +namespace Config { + +Watch* WatchMap::addWatch(SubscriptionCallbacks& callbacks) { + auto watch = std::make_unique(callbacks); + Watch* watch_ptr = watch.get(); + wildcard_watches_.insert(watch_ptr); + watches_.insert(std::move(watch)); + return watch_ptr; +} + +void WatchMap::removeWatch(Watch* watch) { + wildcard_watches_.erase(watch); // may or may not be in there, but we want it gone. + watches_.erase(watch); +} + +AddedRemoved WatchMap::updateWatchInterest(Watch* watch, + const std::set& update_to_these_names) { + if (update_to_these_names.empty()) { + wildcard_watches_.insert(watch); + } else { + wildcard_watches_.erase(watch); + } + + std::vector newly_added_to_watch; + std::set_difference(update_to_these_names.begin(), update_to_these_names.end(), + watch->resource_names_.begin(), watch->resource_names_.end(), + std::inserter(newly_added_to_watch, newly_added_to_watch.begin())); + + std::vector newly_removed_from_watch; + std::set_difference(watch->resource_names_.begin(), watch->resource_names_.end(), + update_to_these_names.begin(), update_to_these_names.end(), + std::inserter(newly_removed_from_watch, newly_removed_from_watch.begin())); + + watch->resource_names_ = update_to_these_names; + + return AddedRemoved(findAdditions(newly_added_to_watch, watch), + findRemovals(newly_removed_from_watch, watch)); +} + +absl::flat_hash_set WatchMap::watchesInterestedIn(const std::string& resource_name) { + absl::flat_hash_set ret = wildcard_watches_; + auto watches_interested = watch_interest_.find(resource_name); + if (watches_interested != watch_interest_.end()) { + for (const auto& watch : watches_interested->second) { + ret.insert(watch); + } + } + return ret; +} + +void WatchMap::onConfigUpdate(const Protobuf::RepeatedPtrField& resources, + const std::string& version_info) { + if (watches_.empty()) { + ENVOY_LOG(warn, "WatchMap::onConfigUpdate: there are no watches!"); + return; + } + SubscriptionCallbacks& name_getter = (*watches_.begin())->callbacks_; + + // Build a map from watches, to the set of updated resources that each watch cares about. Each + // entry in the map is then a nice little bundle that can be fed directly into the individual + // onConfigUpdate()s. + absl::flat_hash_map> per_watch_updates; + for (const auto& r : resources) { + const absl::flat_hash_set& interested_in_r = + watchesInterestedIn(name_getter.resourceName(r)); + for (const auto& interested_watch : interested_in_r) { + per_watch_updates[interested_watch].Add()->CopyFrom(r); + } + } + + // We just bundled up the updates into nice per-watch packages. Now, deliver them. + for (auto& watch : watches_) { + auto this_watch_updates = per_watch_updates.find(watch); + if (this_watch_updates == per_watch_updates.end()) { + // This update included no resources this watch cares about - so we do an empty + // onConfigUpdate(), to notify the watch that its resources - if they existed before this - + // were dropped. + watch->callbacks_.onConfigUpdate({}, version_info); + } else { + watch->callbacks_.onConfigUpdate(this_watch_updates->second, version_info); + } + } +} + +void WatchMap::onConfigUpdate( + const Protobuf::RepeatedPtrField& added_resources, + const Protobuf::RepeatedPtrField& removed_resources, + const std::string& system_version_info) { + // Build a pair of maps: from watches, to the set of resources {added,removed} that each watch + // cares about. Each entry in the map-pair is then a nice little bundle that can be fed directly + // into the individual onConfigUpdate()s. + absl::flat_hash_map> per_watch_added; + for (const auto& r : added_resources) { + const absl::flat_hash_set& interested_in_r = watchesInterestedIn(r.name()); + for (const auto& interested_watch : interested_in_r) { + per_watch_added[interested_watch].Add()->CopyFrom(r); + } + } + absl::flat_hash_map> per_watch_removed; + for (const auto& r : removed_resources) { + const absl::flat_hash_set& interested_in_r = watchesInterestedIn(r); + for (const auto& interested_watch : interested_in_r) { + *per_watch_removed[interested_watch].Add() = r; + } + } + + // We just bundled up the updates into nice per-watch packages. Now, deliver them. + for (const auto& added : per_watch_added) { + const Watch* cur_watch = added.first; + auto removed = per_watch_removed.find(cur_watch); + if (removed == per_watch_removed.end()) { + // additions only, no removals + cur_watch->callbacks_.onConfigUpdate(added.second, {}, system_version_info); + } else { + // both additions and removals + cur_watch->callbacks_.onConfigUpdate(added.second, removed->second, system_version_info); + // Drop the removals now, so the final removals-only pass won't use them. + per_watch_removed.erase(removed); + } + } + // Any removals-only updates will not have been picked up in the per_watch_added loop. + for (auto& removed : per_watch_removed) { + removed.first->callbacks_.onConfigUpdate({}, removed.second, system_version_info); + } +} + +void WatchMap::onConfigUpdateFailed(ConfigUpdateFailureReason reason, const EnvoyException* e) { + for (auto& watch : watches_) { + watch->callbacks_.onConfigUpdateFailed(reason, e); + } +} + +std::set WatchMap::findAdditions(const std::vector& newly_added_to_watch, + Watch* watch) { + std::set newly_added_to_subscription; + for (const auto& name : newly_added_to_watch) { + auto entry = watch_interest_.find(name); + if (entry == watch_interest_.end()) { + newly_added_to_subscription.insert(name); + watch_interest_[name] = {watch}; + } else { + entry->second.insert(watch); + } + } + return newly_added_to_subscription; +} + +std::set +WatchMap::findRemovals(const std::vector& newly_removed_from_watch, Watch* watch) { + std::set newly_removed_from_subscription; + for (const auto& name : newly_removed_from_watch) { + auto entry = watch_interest_.find(name); + RELEASE_ASSERT( + entry != watch_interest_.end(), + fmt::format("WatchMap: tried to remove a watch from untracked resource {}", name)); + + entry->second.erase(watch); + if (entry->second.empty()) { + watch_interest_.erase(entry); + newly_removed_from_subscription.insert(name); + } + } + return newly_removed_from_subscription; +} + +} // namespace Config +} // namespace Envoy diff --git a/source/common/config/watch_map.h b/source/common/config/watch_map.h new file mode 100644 index 000000000000..5e75e5e88dd7 --- /dev/null +++ b/source/common/config/watch_map.h @@ -0,0 +1,115 @@ +#pragma once + +#include +#include +#include + +#include "envoy/config/subscription.h" + +#include "common/common/assert.h" +#include "common/common/logger.h" + +#include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" + +namespace Envoy { +namespace Config { + +struct AddedRemoved { + AddedRemoved(std::set&& added, std::set&& removed) + : added_(std::move(added)), removed_(std::move(removed)) {} + std::set added_; + std::set removed_; +}; + +struct Watch { + Watch(SubscriptionCallbacks& callbacks) : callbacks_(callbacks) {} + SubscriptionCallbacks& callbacks_; + std::set resource_names_; // must be sorted set, for set_difference. +}; + +// NOTE: Users are responsible for eventually calling removeWatch() on the Watch* returned +// by addWatch(). We don't expect there to be new users of this class beyond +// NewGrpcMuxImpl and DeltaSubscriptionImpl (TODO(fredlas) to be renamed). +// +// Manages "watches" of xDS resources. Several xDS callers might ask for a subscription to the same +// resource name "X". The xDS machinery must return to each their very own subscription to X. +// The xDS machinery's "watch" concept accomplishes that, while avoiding parallel redundant xDS +// requests for X. Each of those subscriptions is viewed as a "watch" on X, while behind the scenes +// there is just a single real subscription to that resource name. +// +// This class maintains the watches<-->subscription mapping: it +// 1) delivers updates to all interested watches, and +// 2) tracks which resource names should be {added to,removed from} the subscription when the +// {first,last} watch on a resource name is {added,removed}. +// +// #1 is accomplished by WatchMap's implementation of the SubscriptionCallbacks interface. +// This interface allows the xDS client to just throw each xDS update message it receives directly +// into WatchMap::onConfigUpdate, rather than having to track the various watches' callbacks. +// +// The information for #2 is returned by updateWatchInterest(); the caller should use it to +// update the subscription accordingly. +// +// A WatchMap is assumed to be dedicated to a single type_url type of resource (EDS, CDS, etc). +class WatchMap : public SubscriptionCallbacks, public Logger::Loggable { +public: + WatchMap() = default; + + // Adds 'callbacks' to the WatchMap, with every possible resource being watched. + // (Use updateWatchInterest() to narrow it down to some specific names). + // Returns the newly added watch, to be used with updateWatchInterest and removeWatch. + Watch* addWatch(SubscriptionCallbacks& callbacks); + + // Updates the set of resource names that the given watch should watch. + // Returns any resource name additions/removals that are unique across all watches. That is: + // 1) if 'resources' contains X and no other watch cares about X, X will be in added_. + // 2) if 'resources' does not contain Y, and this watch was the only one that cared about Y, + // Y will be in removed_. + AddedRemoved updateWatchInterest(Watch* watch, + const std::set& update_to_these_names); + + // Expects that the watch to be removed has already had all of its resource names removed via + // updateWatchInterest(). + void removeWatch(Watch* watch); + + // SubscriptionCallbacks + void onConfigUpdate(const Protobuf::RepeatedPtrField& resources, + const std::string& version_info) override; + void onConfigUpdate(const Protobuf::RepeatedPtrField& added_resources, + const Protobuf::RepeatedPtrField& removed_resources, + const std::string& system_version_info) override; + + void onConfigUpdateFailed(ConfigUpdateFailureReason reason, const EnvoyException* e) override; + + std::string resourceName(const ProtobufWkt::Any&) override { NOT_IMPLEMENTED_GCOVR_EXCL_LINE; } + + WatchMap(const WatchMap&) = delete; + WatchMap& operator=(const WatchMap&) = delete; + +private: + // Given a list of names that are new to an individual watch, returns those names that are in fact + // new to the entire subscription. + std::set findAdditions(const std::vector& newly_added_to_watch, + Watch* watch); + + // Given a list of names that an individual watch no longer cares about, returns those names that + // in fact the entire subscription no longer cares about. + std::set findRemovals(const std::vector& newly_removed_from_watch, + Watch* watch); + + // Returns the union of watch_interest_[resource_name] and wildcard_watches_. + absl::flat_hash_set watchesInterestedIn(const std::string& resource_name); + + absl::flat_hash_set> watches_; + + // Watches whose interest set is currently empty, which is interpreted as "everything". + absl::flat_hash_set wildcard_watches_; + + // Maps a resource name to the set of watches interested in that resource. Has two purposes: + // 1) Acts as a reference count; no watches care anymore ==> the resource can be removed. + // 2) Enables efficient lookup of all interested watches when a resource has been updated. + absl::flat_hash_map> watch_interest_; +}; + +} // namespace Config +} // namespace Envoy diff --git a/source/docs/xDS_code_diagram.png b/source/docs/xDS_code_diagram.png new file mode 100644 index 0000000000000000000000000000000000000000..ef4df79cc1e30f59f865d5c29abc91ca05b19f72 GIT binary patch literal 97291 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%0A07Moj7KS0o@imd+yv_n<&&CTakng_yb3_4Oj{ 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 L(bFhWv%dB}cK|?= literal 0 HcmV?d00001 diff --git a/test/common/config/BUILD b/test/common/config/BUILD index 509d423919a9..60101fa4aa22 100644 --- a/test/common/config/BUILD +++ b/test/common/config/BUILD @@ -274,6 +274,17 @@ envoy_cc_test( ], ) +envoy_cc_test( + name = "watch_map_test", + srcs = ["watch_map_test.cc"], + deps = [ + "//source/common/config:watch_map_lib", + "//test/mocks/config:config_mocks", + "//test/test_common:utility_lib", + "@envoy_api//envoy/api/v2:eds_cc", + ], +) + envoy_cc_test( name = "filter_json_test", srcs = ["filter_json_test.cc"], diff --git a/test/common/config/watch_map_test.cc b/test/common/config/watch_map_test.cc new file mode 100644 index 000000000000..543298557fab --- /dev/null +++ b/test/common/config/watch_map_test.cc @@ -0,0 +1,397 @@ +#include + +#include "envoy/api/v2/eds.pb.h" +#include "envoy/common/exception.h" +#include "envoy/stats/scope.h" + +#include "common/config/watch_map.h" + +#include "test/mocks/config/mocks.h" +#include "test/test_common/utility.h" + +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using ::testing::_; +using ::testing::Invoke; + +namespace Envoy { +namespace Config { +namespace { + +class NamedMockSubscriptionCallbacks + : public MockSubscriptionCallbacks { +public: + std::string resourceName(const ProtobufWkt::Any& resource) override { + return TestUtility::anyConvert(resource).cluster_name(); + } +}; + +// expectDeltaAndSotwUpdate() EXPECTs two birds with one function call: we want to cover both SotW +// and delta, which, while mechanically different, can behave identically for our testing purposes. +// Specifically, as a simplification for these tests, every still-present resource is updated in +// every update. Therefore, a resource can never show up in the SotW update but not the delta +// update. We can therefore use the same expected_resources for both. +void expectDeltaAndSotwUpdate( + NamedMockSubscriptionCallbacks& callbacks, + const std::vector& expected_resources, + const std::vector& expected_removals, const std::string& version) { + EXPECT_CALL(callbacks, onConfigUpdate(_, version)) + .WillOnce(Invoke( + [expected_resources](const Protobuf::RepeatedPtrField& gotten_resources, + const std::string&) { + EXPECT_EQ(expected_resources.size(), gotten_resources.size()); + for (size_t i = 0; i < expected_resources.size(); i++) { + envoy::api::v2::ClusterLoadAssignment cur_gotten_resource; + gotten_resources[i].UnpackTo(&cur_gotten_resource); + EXPECT_TRUE(TestUtility::protoEqual(cur_gotten_resource, expected_resources[i])); + } + })); + EXPECT_CALL(callbacks, onConfigUpdate(_, _, _)) + .WillOnce( + Invoke([expected_resources, expected_removals, version]( + const Protobuf::RepeatedPtrField& gotten_resources, + const Protobuf::RepeatedPtrField& removed_resources, + const std::string&) { + EXPECT_EQ(expected_resources.size(), gotten_resources.size()); + for (size_t i = 0; i < expected_resources.size(); i++) { + EXPECT_EQ(gotten_resources[i].version(), version); + envoy::api::v2::ClusterLoadAssignment cur_gotten_resource; + gotten_resources[i].resource().UnpackTo(&cur_gotten_resource); + EXPECT_TRUE(TestUtility::protoEqual(cur_gotten_resource, expected_resources[i])); + } + EXPECT_EQ(expected_removals.size(), removed_resources.size()); + for (size_t i = 0; i < expected_removals.size(); i++) { + EXPECT_EQ(expected_removals[i], removed_resources[i]); + } + })); +} + +// Sometimes we want to verify that a delta onConfigUpdate simply doesn't happen. However, for SotW, +// every update triggers all onConfigUpdate()s, so we should still expect empty calls for that. +void expectNoDeltaUpdate(NamedMockSubscriptionCallbacks& callbacks, const std::string& version) { + EXPECT_CALL(callbacks, onConfigUpdate(_, version)) + .WillOnce(Invoke([](const Protobuf::RepeatedPtrField& gotten_resources, + const std::string&) { EXPECT_EQ(0, gotten_resources.size()); })); + EXPECT_CALL(callbacks, onConfigUpdate(_, _, _)).Times(0); +} + +Protobuf::RepeatedPtrField +wrapInResource(const Protobuf::RepeatedPtrField& anys, + const std::string& version) { + Protobuf::RepeatedPtrField ret; + for (const auto& a : anys) { + envoy::api::v2::ClusterLoadAssignment cur_endpoint; + a.UnpackTo(&cur_endpoint); + auto* cur_resource = ret.Add(); + cur_resource->set_name(cur_endpoint.cluster_name()); + cur_resource->mutable_resource()->CopyFrom(a); + cur_resource->set_version(version); + } + return ret; +} + +// Similar to expectDeltaAndSotwUpdate(), but making the onConfigUpdate() happen, rather than +// EXPECTing it. +void doDeltaAndSotwUpdate(SubscriptionCallbacks& watch_map, + const Protobuf::RepeatedPtrField& sotw_resources, + const std::vector& removed_names, + const std::string& version) { + watch_map.onConfigUpdate(sotw_resources, version); + + Protobuf::RepeatedPtrField delta_resources = + wrapInResource(sotw_resources, version); + Protobuf::RepeatedPtrField removed_names_proto; + for (const auto& n : removed_names) { + *removed_names_proto.Add() = n; + } + watch_map.onConfigUpdate(delta_resources, removed_names_proto, "version1"); +} + +// Tests the simple case of a single watch. Checks that the watch will not be told of updates to +// resources it doesn't care about. Checks that the watch can later decide it does care about them, +// and then receive subsequent updates to them. +TEST(WatchMapTest, Basic) { + NamedMockSubscriptionCallbacks callbacks; + WatchMap watch_map; + Watch* watch = watch_map.addWatch(callbacks); + + { + // The watch is interested in Alice and Bob... + std::set update_to({"alice", "bob"}); + AddedRemoved added_removed = watch_map.updateWatchInterest(watch, update_to); + EXPECT_EQ(update_to, added_removed.added_); + EXPECT_TRUE(added_removed.removed_.empty()); + + // ...the update is going to contain Bob and Carol... + Protobuf::RepeatedPtrField updated_resources; + envoy::api::v2::ClusterLoadAssignment bob; + bob.set_cluster_name("bob"); + updated_resources.Add()->PackFrom(bob); + envoy::api::v2::ClusterLoadAssignment carol; + carol.set_cluster_name("carol"); + updated_resources.Add()->PackFrom(carol); + + // ...so the watch should receive only Bob. + std::vector expected_resources; + expected_resources.push_back(bob); + + expectDeltaAndSotwUpdate(callbacks, expected_resources, {}, "version1"); + doDeltaAndSotwUpdate(watch_map, updated_resources, {}, "version1"); + } + { + // The watch is now interested in Bob, Carol, Dave, Eve... + std::set update_to({"bob", "carol", "dave", "eve"}); + AddedRemoved added_removed = watch_map.updateWatchInterest(watch, update_to); + EXPECT_EQ(std::set({"carol", "dave", "eve"}), added_removed.added_); + EXPECT_EQ(std::set({"alice"}), added_removed.removed_); + + // ...the update is going to contain Alice, Carol, Dave... + Protobuf::RepeatedPtrField updated_resources; + envoy::api::v2::ClusterLoadAssignment alice; + alice.set_cluster_name("alice"); + updated_resources.Add()->PackFrom(alice); + envoy::api::v2::ClusterLoadAssignment carol; + carol.set_cluster_name("carol"); + updated_resources.Add()->PackFrom(carol); + envoy::api::v2::ClusterLoadAssignment dave; + dave.set_cluster_name("dave"); + updated_resources.Add()->PackFrom(dave); + + // ...so the watch should receive only Carol and Dave. + std::vector expected_resources; + expected_resources.push_back(carol); + expected_resources.push_back(dave); + + expectDeltaAndSotwUpdate(callbacks, expected_resources, {"bob"}, "version2"); + doDeltaAndSotwUpdate(watch_map, updated_resources, {"bob"}, "version2"); + } +} + +// Checks the following: +// First watch on a resource name ==> updateWatchInterest() returns "add it to subscription" +// Second watch on that name ==> updateWatchInterest() returns nothing about that name +// Original watch loses interest ==> nothing +// Second watch also loses interest ==> "remove it from subscription" +// NOTE: we need the resource name "dummy" to keep either watch from ever having no names watched, +// which is treated as interest in all names. +TEST(WatchMapTest, Overlap) { + NamedMockSubscriptionCallbacks callbacks1; + NamedMockSubscriptionCallbacks callbacks2; + WatchMap watch_map; + Watch* watch1 = watch_map.addWatch(callbacks1); + Watch* watch2 = watch_map.addWatch(callbacks2); + + Protobuf::RepeatedPtrField updated_resources; + envoy::api::v2::ClusterLoadAssignment alice; + alice.set_cluster_name("alice"); + updated_resources.Add()->PackFrom(alice); + + // First watch becomes interested. + { + std::set update_to({"alice", "dummy"}); + AddedRemoved added_removed = watch_map.updateWatchInterest(watch1, update_to); + EXPECT_EQ(update_to, added_removed.added_); // add to subscription + EXPECT_TRUE(added_removed.removed_.empty()); + watch_map.updateWatchInterest(watch2, {"dummy"}); + + // First watch receives update. + expectDeltaAndSotwUpdate(callbacks1, {alice}, {}, "version1"); + expectNoDeltaUpdate(callbacks2, "version1"); + doDeltaAndSotwUpdate(watch_map, updated_resources, {}, "version1"); + } + // Second watch becomes interested. + { + std::set update_to({"alice", "dummy"}); + AddedRemoved added_removed = watch_map.updateWatchInterest(watch2, update_to); + EXPECT_TRUE(added_removed.added_.empty()); // nothing happens + EXPECT_TRUE(added_removed.removed_.empty()); + + // Both watches receive update. + expectDeltaAndSotwUpdate(callbacks1, {alice}, {}, "version2"); + expectDeltaAndSotwUpdate(callbacks2, {alice}, {}, "version2"); + doDeltaAndSotwUpdate(watch_map, updated_resources, {}, "version2"); + } + // First watch loses interest. + { + AddedRemoved added_removed = watch_map.updateWatchInterest(watch1, {"dummy"}); + EXPECT_TRUE(added_removed.added_.empty()); // nothing happens + EXPECT_TRUE(added_removed.removed_.empty()); + + // *Only* second watch receives update. + expectNoDeltaUpdate(callbacks1, "version3"); + expectDeltaAndSotwUpdate(callbacks2, {alice}, {}, "version3"); + doDeltaAndSotwUpdate(watch_map, updated_resources, {}, "version3"); + } + // Second watch loses interest. + { + AddedRemoved added_removed = watch_map.updateWatchInterest(watch2, {"dummy"}); + EXPECT_TRUE(added_removed.added_.empty()); + EXPECT_EQ(std::set({"alice"}), added_removed.removed_); // remove from subscription + } +} + +// Checks the following: +// First watch on a resource name ==> updateWatchInterest() returns "add it to subscription" +// Watch loses interest ==> "remove it from subscription" +// Second watch on that name ==> "add it to subscription" +// NOTE: we need the resource name "dummy" to keep either watch from ever having no names watched, +// which is treated as interest in all names. +TEST(WatchMapTest, AddRemoveAdd) { + NamedMockSubscriptionCallbacks callbacks1; + NamedMockSubscriptionCallbacks callbacks2; + WatchMap watch_map; + Watch* watch1 = watch_map.addWatch(callbacks1); + Watch* watch2 = watch_map.addWatch(callbacks2); + + Protobuf::RepeatedPtrField updated_resources; + envoy::api::v2::ClusterLoadAssignment alice; + alice.set_cluster_name("alice"); + updated_resources.Add()->PackFrom(alice); + + // First watch becomes interested. + { + std::set update_to({"alice", "dummy"}); + AddedRemoved added_removed = watch_map.updateWatchInterest(watch1, update_to); + EXPECT_EQ(update_to, added_removed.added_); // add to subscription + EXPECT_TRUE(added_removed.removed_.empty()); + watch_map.updateWatchInterest(watch2, {"dummy"}); + + // First watch receives update. + expectDeltaAndSotwUpdate(callbacks1, {alice}, {}, "version1"); + expectNoDeltaUpdate(callbacks2, "version1"); + doDeltaAndSotwUpdate(watch_map, updated_resources, {}, "version1"); + } + // First watch loses interest. + { + AddedRemoved added_removed = watch_map.updateWatchInterest(watch1, {"dummy"}); + EXPECT_TRUE(added_removed.added_.empty()); + EXPECT_EQ(std::set({"alice"}), added_removed.removed_); // remove from subscription + + // (The xDS client should have responded to updateWatchInterest()'s return value by removing + // Alice from the subscription, so onConfigUpdate() calls should be impossible right now.) + } + // Second watch becomes interested. + { + std::set update_to({"alice", "dummy"}); + AddedRemoved added_removed = watch_map.updateWatchInterest(watch2, update_to); + EXPECT_EQ(std::set({"alice"}), added_removed.added_); // add to subscription + EXPECT_TRUE(added_removed.removed_.empty()); + + // *Only* second watch receives update. + expectNoDeltaUpdate(callbacks1, "version2"); + expectDeltaAndSotwUpdate(callbacks2, {alice}, {}, "version2"); + doDeltaAndSotwUpdate(watch_map, updated_resources, {}, "version2"); + } +} + +// Tests that nothing breaks if an update arrives that we entirely do not care about. +TEST(WatchMapTest, UninterestingUpdate) { + NamedMockSubscriptionCallbacks callbacks; + WatchMap watch_map; + Watch* watch = watch_map.addWatch(callbacks); + watch_map.updateWatchInterest(watch, {"alice"}); + + Protobuf::RepeatedPtrField alice_update; + envoy::api::v2::ClusterLoadAssignment alice; + alice.set_cluster_name("alice"); + alice_update.Add()->PackFrom(alice); + + Protobuf::RepeatedPtrField bob_update; + envoy::api::v2::ClusterLoadAssignment bob; + bob.set_cluster_name("bob"); + bob_update.Add()->PackFrom(bob); + + expectNoDeltaUpdate(callbacks, "version1"); + doDeltaAndSotwUpdate(watch_map, bob_update, {}, "version1"); + + expectDeltaAndSotwUpdate(callbacks, {alice}, {}, "version2"); + doDeltaAndSotwUpdate(watch_map, alice_update, {}, "version2"); + + expectNoDeltaUpdate(callbacks, "version3"); + doDeltaAndSotwUpdate(watch_map, bob_update, {}, "version3"); + + // Clean removal of the watch: first update to "interested in nothing", then remove. + watch_map.updateWatchInterest(watch, {}); + watch_map.removeWatch(watch); + + // Finally, test that calling onConfigUpdate on a map with no watches doesn't break. + doDeltaAndSotwUpdate(watch_map, bob_update, {}, "version4"); +} + +// Tests that a watch that specifies no particular resource interest is treated as interested in +// everything. +TEST(WatchMapTest, WatchingEverything) { + NamedMockSubscriptionCallbacks callbacks1; + NamedMockSubscriptionCallbacks callbacks2; + WatchMap watch_map; + /*Watch* watch1 = */ watch_map.addWatch(callbacks1); + Watch* watch2 = watch_map.addWatch(callbacks2); + // watch1 never specifies any names, and so is treated as interested in everything. + watch_map.updateWatchInterest(watch2, {"alice"}); + + Protobuf::RepeatedPtrField updated_resources; + envoy::api::v2::ClusterLoadAssignment alice; + alice.set_cluster_name("alice"); + updated_resources.Add()->PackFrom(alice); + envoy::api::v2::ClusterLoadAssignment bob; + bob.set_cluster_name("bob"); + updated_resources.Add()->PackFrom(bob); + + std::vector expected_resources1; + expected_resources1.push_back(alice); + expected_resources1.push_back(bob); + std::vector expected_resources2; + expected_resources2.push_back(alice); + + expectDeltaAndSotwUpdate(callbacks1, expected_resources1, {}, "version1"); + expectDeltaAndSotwUpdate(callbacks2, expected_resources2, {}, "version1"); + doDeltaAndSotwUpdate(watch_map, updated_resources, {}, "version1"); +} + +// Delta onConfigUpdate has some slightly subtle details with how it handles the three cases where a +// watch receives {only updates, updates+removals, only removals} to its resources. This test +// exercise those cases. Also, the removal-only case tests that SotW does call a watch's +// onConfigUpdate even if none of the watch's interested resources are among the updated resources. +// (Which ensures we deliver empty config updates when a resource is dropped.) +TEST(WatchMapTest, DeltaOnConfigUpdate) { + NamedMockSubscriptionCallbacks callbacks1; + NamedMockSubscriptionCallbacks callbacks2; + NamedMockSubscriptionCallbacks callbacks3; + WatchMap watch_map; + Watch* watch1 = watch_map.addWatch(callbacks1); + Watch* watch2 = watch_map.addWatch(callbacks2); + Watch* watch3 = watch_map.addWatch(callbacks3); + watch_map.updateWatchInterest(watch1, {"updated"}); + watch_map.updateWatchInterest(watch2, {"updated", "removed"}); + watch_map.updateWatchInterest(watch3, {"removed"}); + + Protobuf::RepeatedPtrField update; + envoy::api::v2::ClusterLoadAssignment updated; + updated.set_cluster_name("updated"); + update.Add()->PackFrom(updated); + + expectDeltaAndSotwUpdate(callbacks1, {updated}, {}, "version1"); // only update + expectDeltaAndSotwUpdate(callbacks2, {updated}, {"removed"}, "version1"); // update+remove + expectDeltaAndSotwUpdate(callbacks3, {}, {"removed"}, "version1"); // only remove + doDeltaAndSotwUpdate(watch_map, update, {"removed"}, "version1"); +} + +TEST(WatchMapTest, OnConfigUpdateFailed) { + WatchMap watch_map; + // calling on empty map doesn't break + watch_map.onConfigUpdateFailed(ConfigUpdateFailureReason::UpdateRejected, nullptr); + + NamedMockSubscriptionCallbacks callbacks1; + NamedMockSubscriptionCallbacks callbacks2; + watch_map.addWatch(callbacks1); + watch_map.addWatch(callbacks2); + + EXPECT_CALL(callbacks1, onConfigUpdateFailed(ConfigUpdateFailureReason::UpdateRejected, nullptr)); + EXPECT_CALL(callbacks2, onConfigUpdateFailed(ConfigUpdateFailureReason::UpdateRejected, nullptr)); + watch_map.onConfigUpdateFailed(ConfigUpdateFailureReason::UpdateRejected, nullptr); +} + +} // namespace +} // namespace Config +} // namespace Envoy diff --git a/tools/spelling_dictionary.txt b/tools/spelling_dictionary.txt index 50abfff89e48..3f935e236cef 100644 --- a/tools/spelling_dictionary.txt +++ b/tools/spelling_dictionary.txt @@ -85,6 +85,7 @@ EVAL EVLOOP EVP EWOULDBLOCK +EXPECTs EXPR FAQ FDs @@ -468,6 +469,7 @@ evthread evwatch exe execlp +expectDeltaAndSotwUpdate facto favicon fd @@ -624,6 +626,7 @@ params paren parentid parsers +passthroughs pcall pcap pclose