Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/common/router/scoped_rds.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <memory>
4
#include <string>
5
6
#include "envoy/common/callback.h"
7
#include "envoy/config/core/v3/config_source.pb.h"
8
#include "envoy/config/route/v3/scoped_route.pb.h"
9
#include "envoy/config/route/v3/scoped_route.pb.validate.h"
10
#include "envoy/config/subscription.h"
11
#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h"
12
#include "envoy/router/route_config_provider_manager.h"
13
#include "envoy/router/scopes.h"
14
#include "envoy/service/discovery/v3/discovery.pb.h"
15
#include "envoy/stats/scope.h"
16
17
#include "source/common/config/config_provider_impl.h"
18
#include "source/common/config/subscription_base.h"
19
#include "source/common/init/manager_impl.h"
20
#include "source/common/router/rds_impl.h"
21
#include "source/common/router/scoped_config_impl.h"
22
23
namespace Envoy {
24
namespace Router {
25
26
// Scoped routing configuration utilities.
27
namespace ScopedRoutesConfigProviderUtil {
28
29
// If enabled in the HttpConnectionManager config, returns a ConfigProvider for scoped routing
30
// configuration.
31
Envoy::Config::ConfigProviderPtr create(
32
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
33
        config,
34
    Server::Configuration::ServerFactoryContext& factory_context, Init::Manager& init_manager,
35
    const std::string& stat_prefix,
36
    Envoy::Config::ConfigProviderManager& scoped_routes_config_provider_manager);
37
38
// If enabled in the HttpConnectionManager config, returns a ConfigProvider for scoped routing
39
// configuration.
40
ScopeKeyBuilderPtr createScopeKeyBuilder(
41
    const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
42
        config);
43
44
} // namespace ScopedRoutesConfigProviderUtil
45
46
class ScopedRoutesConfigProviderManager;
47
48
// A ConfigProvider for inline scoped routing configuration.
49
// InlineScopedRoutesConfigProvider is not fully implemented at this point. It doesn't load
50
// ScopedRouteConfigurations and propagate them to worker threads. If
51
// InlineScopedRoutesConfigProvider is fully implemented, when it is loading
52
// ScopedRouteConfiguration, the on demand field should be ignored and all scopes should be loaded
53
// eagerly.
54
class InlineScopedRoutesConfigProvider : public Envoy::Config::ImmutableConfigProviderBase {
55
public:
56
  InlineScopedRoutesConfigProvider(ProtobufTypes::ConstMessagePtrVector&& config_protos,
57
                                   std::string name,
58
                                   Server::Configuration::ServerFactoryContext& factory_context,
59
                                   ScopedRoutesConfigProviderManager& config_provider_manager,
60
                                   envoy::config::core::v3::ConfigSource rds_config_source);
61
62
159
  ~InlineScopedRoutesConfigProvider() override = default;
63
64
0
  const std::string& name() const { return name_; }
65
66
  // Envoy::Config::ConfigProvider
67
0
  Envoy::Config::ConfigProvider::ConfigProtoVector getConfigProtos() const override {
68
0
    Envoy::Config::ConfigProvider::ConfigProtoVector out_protos;
69
0
    std::for_each(scopes_.begin(), scopes_.end(),
70
0
                  [&out_protos](const ScopedRouteInfoConstSharedPtr& scope) {
71
0
                    out_protos.push_back(&scope->configProto());
72
0
                  });
73
0
    return out_protos;
74
0
  }
75
76
0
  ConfigConstSharedPtr getConfig() const override { return config_; }
77
78
private:
79
  const std::string name_;
80
  const std::vector<ScopedRouteInfoConstSharedPtr> scopes_;
81
  ConfigConstSharedPtr config_;
82
  const envoy::config::core::v3::ConfigSource rds_config_source_;
83
};
84
85
/**
86
 * All SRDS stats. @see stats_macros.h
87
 */
88
// clang-format off
89
#define ALL_SCOPED_RDS_STATS(COUNTER, GAUGE)                                                       \
90
  COUNTER(config_reload)                                                                           \
91
  COUNTER(update_empty)                                                                            \
92
  GAUGE(all_scopes, Accumulate)                                                                    \
93
  GAUGE(config_reload_time_ms, NeverImport)                                                        \
94
  GAUGE(on_demand_scopes, Accumulate)                                                              \
95
  GAUGE(active_scopes, Accumulate)
96
97
// clang-format on
98
99
struct ScopedRdsStats {
100
  ALL_SCOPED_RDS_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT)
101
102
0
  static ScopedRdsStats generateStats(const std::string& prefix, Stats::Scope& scope) {
103
0
    return ScopedRdsStats{
104
0
        ALL_SCOPED_RDS_STATS(POOL_COUNTER_PREFIX(scope, prefix), POOL_GAUGE_PREFIX(scope, prefix))};
105
0
  }
106
};
107
108
// A scoped RDS subscription to be used with the dynamic scoped RDS ConfigProvider.
109
class ScopedRdsConfigSubscription
110
    : public Envoy::Config::DeltaConfigSubscriptionInstance,
111
      public Envoy::Config::SubscriptionBase<envoy::config::route::v3::ScopedRouteConfiguration> {
112
public:
113
  using ScopedRouteConfigurationMap =
114
      std::map<std::string, envoy::config::route::v3::ScopedRouteConfiguration>;
115
116
  ScopedRdsConfigSubscription(
117
      const envoy::extensions::filters::network::http_connection_manager::v3::ScopedRds& scoped_rds,
118
      const uint64_t manager_identifier, const std::string& name,
119
      Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix,
120
      envoy::config::core::v3::ConfigSource rds_config_source,
121
      RouteConfigProviderManager& route_config_provider_manager,
122
      ScopedRoutesConfigProviderManager& config_provider_manager);
123
124
43
  ~ScopedRdsConfigSubscription() override = default;
125
126
0
  const std::string& name() const { return name_; }
127
128
0
  const ScopedRouteMap& scopedRouteMap() const { return scoped_route_map_; }
129
130
  void
131
  onDemandRdsUpdate(std::shared_ptr<Router::ScopeKey> scope_key,
132
                    Event::Dispatcher& thread_local_dispatcher,
133
                    Http::RouteConfigUpdatedCallback&& route_config_updated_cb,
134
                    std::weak_ptr<Envoy::Config::ConfigSubscriptionCommonBase> weak_subscription);
135
136
private:
137
  // A helper class that takes care of the life cycle management of a RDS route provider and the
138
  // update callback handle.
139
  struct RdsRouteConfigProviderHelper {
140
    RdsRouteConfigProviderHelper(
141
        ScopedRdsConfigSubscription& parent, std::string scope_name,
142
        envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds,
143
        Init::Manager& init_manager);
144
145
    RdsRouteConfigProviderHelper(ScopedRdsConfigSubscription& parent, std::string scope_name);
146
147
0
    ~RdsRouteConfigProviderHelper() {
148
      // Only remove the rds update when the rds provider has been initialized.
149
0
      if (route_provider_) {
150
0
        parent_.stats_.active_scopes_.dec();
151
0
      }
152
0
      if (on_demand_) {
153
0
        parent_.stats_.on_demand_scopes_.dec();
154
0
      }
155
0
    }
156
0
    ConfigConstSharedPtr routeConfig() { return route_provider_->configCast(); }
157
158
    void addOnDemandUpdateCallback(std::function<void()> callback);
159
160
    // Runs all the callback from worker thread to continue filter chain.
161
    void runOnDemandUpdateCallback();
162
163
    // If route provider has not been initialized, initialize it.
164
    void maybeInitRdsConfigProvider();
165
166
    // Initialize route provider and register for rds update.
167
    void initRdsConfigProvider(
168
        envoy::extensions::filters::network::http_connection_manager::v3::Rds& rds,
169
        Init::Manager& init_manager);
170
171
    ScopedRdsConfigSubscription& parent_;
172
    std::string scope_name_;
173
    bool on_demand_;
174
    RdsRouteConfigProviderImplSharedPtr route_provider_;
175
    // This handle_ is owned by the route config provider's RDS subscription, when the helper
176
    // destructs, the handle is deleted as well.
177
    Common::CallbackHandlePtr rds_update_callback_handle_;
178
    std::vector<std::function<void()>> on_demand_update_callbacks_;
179
  };
180
181
  using RdsRouteConfigProviderHelperPtr = std::unique_ptr<RdsRouteConfigProviderHelper>;
182
183
  // Adds or updates scopes, create a new RDS provider for each resource, if an exception is thrown
184
  // during updating, the exception message is collected via the exception messages vector.
185
  // Returns a failed status if the operation was unsuccessful. If successful,
186
  // returns a boolean indicating if any scopes were applied.
187
  absl::StatusOr<bool>
188
  addOrUpdateScopes(const std::vector<Envoy::Config::DecodedResourceRef>& resources,
189
                    Init::Manager& init_manager, const std::string& version_info);
190
  // Removes given scopes from the managed set of scopes.
191
  // Returns a list of to be removed helpers which is temporally held in the onConfigUpdate method,
192
  // to make sure new scopes sharing the same RDS source configs could reuse the subscriptions.
193
  std::list<RdsRouteConfigProviderHelperPtr>
194
  removeScopes(const Protobuf::RepeatedPtrField<std::string>& scope_names,
195
               const std::string& version_info);
196
197
  // Envoy::Config::DeltaConfigSubscriptionInstance
198
0
  void start() override { subscription_->start({}); }
199
200
  // Detect scope name and scope key conflict between added scopes or between added scopes and old
201
  // scopes. Some removed scopes may be in added resources list, instead of being removed, they
202
  // should be updated, so only return scope names that will disappear after update. If conflict
203
  // detected, fill exception_msg with information about scope conflict and return.
204
  Protobuf::RepeatedPtrField<std::string> detectUpdateConflictAndCleanupRemoved(
205
      const std::vector<Envoy::Config::DecodedResourceRef>& added_resources,
206
      const Protobuf::RepeatedPtrField<std::string>& removed_resources, std::string& exception_msg);
207
208
  // Envoy::Config::SubscriptionCallbacks
209
210
  // NOTE: both delta form and state-of-the-world form onConfigUpdate(resources, version_info) will
211
  // throw an EnvoyException or return failure on any error and essentially reject an update.
212
  absl::Status onConfigUpdate(const std::vector<Envoy::Config::DecodedResourceRef>& resources,
213
                              const std::string& version_info) override;
214
  absl::Status onConfigUpdate(const std::vector<Envoy::Config::DecodedResourceRef>& added_resources,
215
                              const Protobuf::RepeatedPtrField<std::string>& removed_resources,
216
                              const std::string& system_version_info) override;
217
  void onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason reason,
218
0
                            const EnvoyException*) override {
219
0
    ASSERT(Envoy::Config::ConfigUpdateFailureReason::ConnectionFailure != reason);
220
0
    DeltaConfigSubscriptionInstance::onConfigUpdateFailed();
221
0
  }
222
  // Propagate RDS updates to ScopeConfigImpl in workers.
223
  void onRdsConfigUpdate(const std::string& scope_name, ConfigConstSharedPtr new_rds_config);
224
225
  // ScopedRouteInfo by scope name.
226
  ScopedRouteMap scoped_route_map_;
227
228
  // For creating RDS subscriptions.
229
  Server::Configuration::ServerFactoryContext& factory_context_;
230
  const std::string name_;
231
  // Stats must outlive subscription.
232
  Stats::ScopeSharedPtr scope_;
233
  ScopedRdsStats stats_;
234
  Envoy::Config::SubscriptionPtr subscription_;
235
  const envoy::config::core::v3::ConfigSource rds_config_source_;
236
  const std::string stat_prefix_;
237
  RouteConfigProviderManager& route_config_provider_manager_;
238
239
  // RdsRouteConfigProvider by scope name.
240
  absl::flat_hash_map<std::string, RdsRouteConfigProviderHelperPtr> route_provider_by_scope_;
241
  // A map of (hash, scope-name), used to detect the key conflict between scopes.
242
  absl::flat_hash_map<uint64_t, std::string> scope_name_by_hash_;
243
};
244
245
using ScopedRdsConfigSubscriptionSharedPtr = std::shared_ptr<ScopedRdsConfigSubscription>;
246
247
// A ConfigProvider for scoped RDS that dynamically fetches scoped routing configuration via a
248
// subscription.
249
class ScopedRdsConfigProvider : public Envoy::Config::MutableConfigProviderCommonBase {
250
public:
251
  ScopedRdsConfigProvider(ScopedRdsConfigSubscriptionSharedPtr&& subscription);
252
253
0
  ScopedRdsConfigSubscription& subscription() const {
254
0
    return *static_cast<ScopedRdsConfigSubscription*>(subscription_.get());
255
0
  }
256
  void onDemandRdsUpdate(std::shared_ptr<Router::ScopeKey> scope_key,
257
                         Event::Dispatcher& thread_local_dispatcher,
258
0
                         Http::RouteConfigUpdatedCallback&& route_config_updated_cb) const {
259
0
    subscription().onDemandRdsUpdate(
260
0
        std::move(scope_key), thread_local_dispatcher, std::move(route_config_updated_cb),
261
0
        std::weak_ptr<Envoy::Config::ConfigSubscriptionCommonBase>(subscription_));
262
0
  }
263
};
264
265
// A ConfigProviderManager for scoped routing configuration that creates static/inline and dynamic
266
// (xds) config providers.
267
class ScopedRoutesConfigProviderManager : public Envoy::Config::ConfigProviderManagerImplBase {
268
public:
269
  ScopedRoutesConfigProviderManager(
270
      OptRef<Server::Admin> admin,
271
      Router::RouteConfigProviderManager& route_config_provider_manager)
272
      : Envoy::Config::ConfigProviderManagerImplBase(admin, "route_scopes"),
273
2.34k
        route_config_provider_manager_(route_config_provider_manager) {}
274
275
  ~ScopedRoutesConfigProviderManager() override = default;
276
277
  // Envoy::Config::ConfigProviderManagerImplBase
278
  ProtobufTypes::MessagePtr dumpConfigs(const Matchers::StringMatcher& name_matcher) const override;
279
280
  // Envoy::Config::ConfigProviderManager
281
  Envoy::Config::ConfigProviderPtr
282
  createXdsConfigProvider(const Protobuf::Message& config_source_proto,
283
                          Server::Configuration::ServerFactoryContext& factory_context,
284
                          Init::Manager& init_manager, const std::string& stat_prefix,
285
                          const Envoy::Config::ConfigProviderManager::OptionalArg& optarg) override;
286
  Envoy::Config::ConfigProviderPtr createStaticConfigProvider(
287
      std::vector<std::unique_ptr<const Protobuf::Message>>&& config_protos,
288
      Server::Configuration::ServerFactoryContext& factory_context,
289
      const Envoy::Config::ConfigProviderManager::OptionalArg& optarg) override;
290
291
3.36k
  RouteConfigProviderManager& routeConfigProviderManager() {
292
3.36k
    return route_config_provider_manager_;
293
3.36k
  }
294
295
private:
296
  RouteConfigProviderManager& route_config_provider_manager_;
297
};
298
299
using ScopedRoutesConfigProviderManagerPtr = std::unique_ptr<ScopedRoutesConfigProviderManager>;
300
using ScopedRoutesConfigProviderManagerSharedPtr =
301
    std::shared_ptr<ScopedRoutesConfigProviderManager>;
302
303
// The optional argument passed to the ConfigProviderManager::create*() functions.
304
class ScopedRoutesConfigProviderManagerOptArg
305
    : public Envoy::Config::ConfigProviderManager::OptionalArg {
306
public:
307
  ScopedRoutesConfigProviderManagerOptArg(
308
      std::string scoped_routes_name,
309
      const envoy::config::core::v3::ConfigSource& rds_config_source)
310
270
      : scoped_routes_name_(std::move(scoped_routes_name)), rds_config_source_(rds_config_source) {}
311
312
  const std::string scoped_routes_name_;
313
  const envoy::config::core::v3::ConfigSource& rds_config_source_;
314
};
315
316
class SrdsFactoryDefault : public SrdsFactory {
317
public:
318
  // UntypedFactory
319
72
  virtual std::string name() const override { return "envoy.srds_factory.default"; }
320
321
  virtual std::unique_ptr<Envoy::Config::ConfigProviderManager>
322
  createScopedRoutesConfigProviderManager(
323
      Server::Configuration::ServerFactoryContext& factory_context,
324
2.34k
      RouteConfigProviderManager& route_config_provider_manager) override {
325
2.34k
    return std::make_unique<Router::ScopedRoutesConfigProviderManager>(
326
2.34k
        factory_context.admin(), route_config_provider_manager);
327
2.34k
  }
328
329
  Envoy::Config::ConfigProviderPtr createConfigProvider(
330
      const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
331
          config,
332
      Server::Configuration::ServerFactoryContext& factory_context, const std::string& stat_prefix,
333
270
      Envoy::Config::ConfigProviderManager& scoped_routes_config_provider_manager) override {
334
270
    return Router::ScopedRoutesConfigProviderUtil::create(
335
270
        config, factory_context, factory_context.initManager(), stat_prefix,
336
270
        scoped_routes_config_provider_manager);
337
270
  }
338
339
  // If enabled in the HttpConnectionManager config, returns a ConfigProvider for scoped routing
340
  // configuration.
341
  ScopeKeyBuilderPtr createScopeKeyBuilder(
342
      const envoy::extensions::filters::network::http_connection_manager::v3::HttpConnectionManager&
343
205
          config) override {
344
205
    return Router::ScopedRoutesConfigProviderUtil::createScopeKeyBuilder(config);
345
205
  }
346
};
347
348
} // namespace Router
349
} // namespace Envoy