Coverage Report

Created: 2023-11-12 09:30

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