-
Notifications
You must be signed in to change notification settings - Fork 5.5k
config: fix a bug where the on demand subscription not works #46216
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| Fixed a bug in on-demand xDS where a resource requested after the initial subscription could be | ||
| silently dropped instead of delivered. An on-demand update only updated the subscription sent to | ||
| the management server, not the internal watch routing, so the server's response for the requested | ||
| resource matched no watch and was discarded. This affected on-demand cluster discovery (ODCDS) when | ||
| requesting a second, different cluster, and VHDS virtual hosts under a route configuration. | ||
| On-demand requests now also register watch routing, so these responses are delivered. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -246,7 +246,7 @@ GrpcMuxWatchPtr NewGrpcMuxImpl::addWatch(const std::string& type_url, | |
| auto entry = subscriptions_.find(type_url); | ||
| if (entry == subscriptions_.end()) { | ||
| // We don't yet have a subscription for type_url! Make one! | ||
| entry = addSubscription(type_url, options.use_namespace_matching_); | ||
| entry = addSubscription(type_url); | ||
| } | ||
|
|
||
| Watch* watch = entry->second->watch_map_.addWatch(callbacks, *resource_decoder); | ||
|
|
@@ -293,13 +293,9 @@ NewGrpcMuxImpl::updateMuxSource(Grpc::RawAsyncClientSharedPtr&& primary_async_cl | |
| // Updates the list of resource names watched by the given watch. If an added name is new across | ||
| // the whole subscription, or if a removed name has no other watch interested in it, then the | ||
| // subscription will enqueue and attempt to send an appropriate discovery request. | ||
| void NewGrpcMuxImpl::updateWatch(const std::string& type_url, Watch* watch, | ||
| const absl::flat_hash_set<std::string>& resources, | ||
| const SubscriptionOptions& options) { | ||
| ASSERT(watch != nullptr); | ||
| auto sub = subscriptions_.find(type_url); | ||
| RELEASE_ASSERT(sub != subscriptions_.end(), | ||
| fmt::format("Watch of {} has no subscription to update.", type_url)); | ||
| absl::flat_hash_set<std::string> | ||
| NewGrpcMuxImpl::effectiveResources(const absl::flat_hash_set<std::string>& resources, | ||
| const SubscriptionOptions& options) { | ||
| // We need to prepare xdstp:// resources for the transport, by normalizing and adding any extra | ||
| // context parameters. | ||
| absl::flat_hash_set<std::string> effective_resources; | ||
|
|
@@ -320,32 +316,43 @@ void NewGrpcMuxImpl::updateWatch(const std::string& type_url, Watch* watch, | |
| effective_resources.insert(resource); | ||
| } | ||
| } | ||
| return effective_resources; | ||
| } | ||
|
|
||
| void NewGrpcMuxImpl::updateWatch(const std::string& type_url, Watch* watch, | ||
| const absl::flat_hash_set<std::string>& resources, | ||
| const SubscriptionOptions& options) { | ||
| ASSERT(watch != nullptr); | ||
| auto sub = subscriptions_.find(type_url); | ||
| RELEASE_ASSERT(sub != subscriptions_.end(), | ||
| fmt::format("Watch of {} has no subscription to update.", type_url)); | ||
| const absl::flat_hash_set<std::string> effective_resources = | ||
| effectiveResources(resources, options); | ||
| auto added_removed = sub->second->watch_map_.updateWatchInterest(watch, effective_resources); | ||
| if (xds_config_tracker_.has_value() && !added_removed.removed_.empty()) { | ||
| for (absl::string_view resource : added_removed.removed_) { | ||
| xds_config_tracker_->onResourceUnsubscribed(type_url, resource); | ||
| } | ||
| } | ||
| if (options.use_namespace_matching_) { | ||
| // This is to prevent sending out of requests that contain prefixes instead of resource names | ||
| sub->second->sub_state_.updateSubscriptionInterest({}, {}); | ||
| } else { | ||
| sub->second->sub_state_.updateSubscriptionInterest(added_removed.added_, | ||
| added_removed.removed_); | ||
| } | ||
| sub->second->sub_state_.updateSubscriptionInterest(added_removed.added_, added_removed.removed_); | ||
|
Comment on lines
-329
to
+337
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The use_namespace_matching_ here make it's impossible to subscribe other resource in the Now, we will always respect the resources set provided by the |
||
| // Tell the server about our change in interest, if any. | ||
| if (sub->second->sub_state_.subscriptionUpdatePending()) { | ||
| trySendDiscoveryRequests(); | ||
| } | ||
| } | ||
|
|
||
| void NewGrpcMuxImpl::requestOnDemandUpdate(const std::string& type_url, | ||
| const absl::flat_hash_set<std::string>& for_update) { | ||
| void NewGrpcMuxImpl::appendWatch(const std::string& type_url, Watch* watch, | ||
| const absl::flat_hash_set<std::string>& resources, | ||
| const SubscriptionOptions& options) { | ||
| ASSERT(watch != nullptr); | ||
| auto sub = subscriptions_.find(type_url); | ||
| RELEASE_ASSERT(sub != subscriptions_.end(), | ||
| fmt::format("Watch of {} has no subscription to update.", type_url)); | ||
| sub->second->sub_state_.updateSubscriptionInterest(for_update, {}); | ||
| // Tell the server about our change in interest, if any. | ||
| // Additionally update the watch-map routing, then subscribe to whatever became newly interesting | ||
| // across the whole subscription. This keeps watch_interest_ and the subscription consistent. | ||
| auto added_removed = | ||
| sub->second->watch_map_.appendWatchInterest(watch, effectiveResources(resources, options)); | ||
| sub->second->sub_state_.updateSubscriptionInterest(added_removed.added_, {}); | ||
| if (sub->second->sub_state_.subscriptionUpdatePending()) { | ||
| trySendDiscoveryRequests(); | ||
| } | ||
|
|
@@ -359,18 +366,27 @@ void NewGrpcMuxImpl::removeWatch(const std::string& type_url, Watch* watch) { | |
| entry->second->watch_map_.removeWatch(watch); | ||
| } | ||
|
|
||
| void NewGrpcMuxImpl::accept(const std::string& type_url, Watch* watch, | ||
| const absl::flat_hash_set<std::string>& patterns) { | ||
| ASSERT(watch != nullptr); | ||
| auto sub = subscriptions_.find(type_url); | ||
| RELEASE_ASSERT(sub != subscriptions_.end(), | ||
| fmt::format("Watch of {} has no subscription to update.", type_url)); | ||
| // Glob interest affects routing only; the subscription sent to the server is left untouched. | ||
| sub->second->watch_map_.accept(watch, patterns); | ||
| } | ||
|
|
||
| NewGrpcMuxImpl::SubscriptionsMap::iterator | ||
| NewGrpcMuxImpl::addSubscription(const std::string& type_url, const bool use_namespace_matching) { | ||
| NewGrpcMuxImpl::addSubscription(const std::string& type_url) { | ||
| // Resource cache is only used for EDS resources. | ||
| EdsResourcesCacheOptRef resources_cache{std::nullopt}; | ||
| if (eds_resources_cache_ && | ||
| (type_url == Config::getTypeUrl<envoy::config::endpoint::v3::ClusterLoadAssignment>())) { | ||
| resources_cache = makeOptRefFromPtr(eds_resources_cache_.get()); | ||
| } | ||
| auto [it, success] = subscriptions_.emplace( | ||
| type_url, std::make_unique<SubscriptionStuff>(type_url, use_namespace_matching, dispatcher_, | ||
| config_validators_.get(), xds_config_tracker_, | ||
| resources_cache)); | ||
| type_url, std::make_unique<SubscriptionStuff>(type_url, dispatcher_, config_validators_.get(), | ||
| xds_config_tracker_, resources_cache)); | ||
| // Insertion must succeed, as the addSubscription method is only called if | ||
| // the map doesn't have the type_url. | ||
| ASSERT(success); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a breaking change with the VHDS default wildcard subscription?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, this PR didn't change any behavior. The VHDS worked in a special way before.
It will specific a route configuration name (for example
rc) in thestart()But thisrcwill not be sent out because theuse_namespace_matchingwon't add anything to the subscription state. See the #46216 (comment)Then this
rcwill be used to match received resources based on prefix matching.For control plane's perspective, nothing is changed.