Line data Source code
1 : #include "source/common/rds/rds_route_config_subscription.h"
2 :
3 : #include "source/common/common/logger.h"
4 : #include "source/common/rds/util.h"
5 :
6 : namespace Envoy {
7 : namespace Rds {
8 :
9 : RdsRouteConfigSubscription::RdsRouteConfigSubscription(
10 : RouteConfigUpdatePtr&& config_update,
11 : Envoy::Config::OpaqueResourceDecoderSharedPtr&& resource_decoder,
12 : const envoy::config::core::v3::ConfigSource& config_source,
13 : const std::string& route_config_name, const uint64_t manager_identifier,
14 : Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix,
15 : const std::string& rds_type, RouteConfigProviderManager& route_config_provider_manager)
16 : : route_config_name_(route_config_name),
17 : scope_(factory_context.scope().createScope(stat_prefix + route_config_name_ + ".")),
18 : factory_context_(factory_context),
19 : parent_init_target_(
20 : fmt::format("RdsRouteConfigSubscription {} init {}", rds_type, route_config_name_),
21 50 : [this]() { local_init_manager_.initialize(local_init_watcher_); }),
22 : local_init_watcher_(fmt::format("{} local-init-watcher {}", rds_type, route_config_name_),
23 50 : [this]() { parent_init_target_.ready(); }),
24 : local_init_target_(fmt::format("RdsRouteConfigSubscription {} local-init-target {}", rds_type,
25 : route_config_name_),
26 50 : [this]() { subscription_->start({route_config_name_}); }),
27 : local_init_manager_(fmt::format("{} local-init-manager {}", rds_type, route_config_name_)),
28 : stat_prefix_(stat_prefix), rds_type_(rds_type),
29 : stats_({ALL_RDS_STATS(POOL_COUNTER(*scope_), POOL_GAUGE(*scope_))}),
30 : route_config_provider_manager_(route_config_provider_manager),
31 : manager_identifier_(manager_identifier), config_update_info_(std::move(config_update)),
32 50 : resource_decoder_(std::move(resource_decoder)) {
33 50 : const auto resource_type = route_config_provider_manager_.protoTraits().resourceType();
34 50 : subscription_ =
35 50 : factory_context.clusterManager().subscriptionFactory().subscriptionFromConfigSource(
36 50 : config_source, Envoy::Grpc::Common::typeUrl(resource_type), *scope_, *this,
37 50 : resource_decoder_, {});
38 50 : local_init_manager_.add(local_init_target_);
39 50 : }
40 :
41 50 : RdsRouteConfigSubscription::~RdsRouteConfigSubscription() {
42 : // If we get destroyed during initialization, make sure we signal that we "initialized".
43 50 : local_init_target_.ready();
44 :
45 : // The ownership of RdsRouteConfigProviderImpl is shared among all HttpConnectionManagers that
46 : // hold a shared_ptr to it. The RouteConfigProviderManager holds weak_ptrs to the
47 : // RdsRouteConfigProviders. Therefore, the map entry for the RdsRouteConfigProvider has to get
48 : // cleaned by the RdsRouteConfigProvider's destructor.
49 50 : route_config_provider_manager_.eraseDynamicProvider(manager_identifier_);
50 50 : }
51 :
52 : absl::Status RdsRouteConfigSubscription::onConfigUpdate(
53 : const std::vector<Envoy::Config::DecodedResourceRef>& resources,
54 100 : const std::string& version_info) {
55 100 : if (resources.empty()) {
56 0 : ENVOY_LOG(debug, "Missing {} RouteConfiguration for {} in onConfigUpdate()", rds_type_,
57 0 : route_config_name_);
58 0 : stats_.update_empty_.inc();
59 0 : local_init_target_.ready();
60 0 : return absl::OkStatus();
61 0 : }
62 100 : if (resources.size() != 1) {
63 0 : return absl::InvalidArgumentError(
64 0 : fmt::format("Unexpected {} resource length: {}", rds_type_, resources.size()));
65 0 : }
66 :
67 100 : const auto& route_config = resources[0].get().resource();
68 100 : Protobuf::ReflectableMessage reflectable_config = createReflectableMessage(route_config);
69 100 : if (reflectable_config->GetDescriptor()->full_name() !=
70 100 : route_config_provider_manager_.protoTraits().resourceType()) {
71 0 : return absl::InvalidArgumentError(
72 0 : fmt::format("Unexpected {} configuration type (expecting {}): {}", rds_type_,
73 0 : route_config_provider_manager_.protoTraits().resourceType(),
74 0 : reflectable_config->GetDescriptor()->full_name()));
75 0 : }
76 100 : if (resourceName(route_config_provider_manager_.protoTraits(), route_config) !=
77 100 : route_config_name_) {
78 0 : return absl::InvalidArgumentError(
79 0 : fmt::format("Unexpected {} configuration (expecting {}): {}", rds_type_, route_config_name_,
80 0 : resourceName(route_config_provider_manager_.protoTraits(), route_config)));
81 0 : }
82 100 : std::unique_ptr<Init::ManagerImpl> noop_init_manager;
83 100 : std::unique_ptr<Cleanup> resume_rds;
84 100 : if (config_update_info_->onRdsUpdate(route_config, version_info)) {
85 36 : stats_.config_reload_.inc();
86 36 : stats_.config_reload_time_ms_.set(DateUtil::nowToMilliseconds(factory_context_.timeSource()));
87 :
88 36 : beforeProviderUpdate(noop_init_manager, resume_rds);
89 :
90 36 : ENVOY_LOG(debug, "rds: loading new configuration: config_name={} hash={}", route_config_name_,
91 36 : config_update_info_->configHash());
92 :
93 36 : if (route_config_provider_ != nullptr) {
94 36 : THROW_IF_NOT_OK(route_config_provider_->onConfigUpdate());
95 36 : }
96 :
97 36 : afterProviderUpdate();
98 36 : }
99 :
100 100 : local_init_target_.ready();
101 100 : return absl::OkStatus();
102 100 : }
103 :
104 : absl::Status RdsRouteConfigSubscription::onConfigUpdate(
105 : const std::vector<Envoy::Config::DecodedResourceRef>& added_resources,
106 16 : const Protobuf::RepeatedPtrField<std::string>& removed_resources, const std::string&) {
107 16 : if (!removed_resources.empty()) {
108 : // TODO(#2500) when on-demand resource loading is supported, an RDS removal may make sense
109 : // (see discussion in #6879), and so we should do something other than ignoring here.
110 0 : ENVOY_LOG(trace,
111 0 : "Server sent a delta {} update attempting to remove a resource (name: {}). Ignoring.",
112 0 : rds_type_, removed_resources[0]);
113 0 : }
114 16 : if (!added_resources.empty()) {
115 16 : return onConfigUpdate(added_resources, added_resources[0].get().version());
116 16 : }
117 0 : return absl::OkStatus();
118 16 : }
119 :
120 : void RdsRouteConfigSubscription::onConfigUpdateFailed(
121 0 : Envoy::Config::ConfigUpdateFailureReason reason, const EnvoyException*) {
122 0 : ASSERT(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure != reason);
123 : // We need to allow server startup to continue, even if we have a bad
124 : // config.
125 0 : local_init_target_.ready();
126 0 : }
127 :
128 : } // namespace Rds
129 : } // namespace Envoy
|