Coverage Report

Created: 2024-09-19 09:45

/proc/self/cwd/source/common/runtime/runtime_impl.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <cstdint>
4
#include <memory>
5
#include <string>
6
7
#include "envoy/api/api.h"
8
#include "envoy/common/exception.h"
9
#include "envoy/common/random_generator.h"
10
#include "envoy/config/bootstrap/v3/bootstrap.pb.h"
11
#include "envoy/config/core/v3/config_source.pb.h"
12
#include "envoy/config/subscription.h"
13
#include "envoy/init/manager.h"
14
#include "envoy/runtime/runtime.h"
15
#include "envoy/service/discovery/v3/discovery.pb.h"
16
#include "envoy/service/runtime/v3/rtds.pb.h"
17
#include "envoy/service/runtime/v3/rtds.pb.validate.h"
18
#include "envoy/stats/stats_macros.h"
19
#include "envoy/stats/store.h"
20
#include "envoy/thread_local/thread_local.h"
21
#include "envoy/type/v3/percent.pb.h"
22
#include "envoy/upstream/cluster_manager.h"
23
24
#include "source/common/common/assert.h"
25
#include "source/common/common/logger.h"
26
#include "source/common/common/thread.h"
27
#include "source/common/config/subscription_base.h"
28
#include "source/common/init/manager_impl.h"
29
#include "source/common/init/target_impl.h"
30
#include "source/common/singleton/threadsafe_singleton.h"
31
32
#include "absl/container/node_hash_map.h"
33
#include "absl/status/statusor.h"
34
#include "spdlog/spdlog.h"
35
36
namespace Envoy {
37
namespace Runtime {
38
39
using RuntimeSingleton = ThreadSafeSingleton<Loader>;
40
41
/**
42
 * All runtime stats. @see stats_macros.h
43
 */
44
#define ALL_RUNTIME_STATS(COUNTER, GAUGE)                                                          \
45
55.3k
  COUNTER(deprecated_feature_use)                                                                  \
46
55.3k
  COUNTER(load_error)                                                                              \
47
55.3k
  COUNTER(load_success)                                                                            \
48
55.3k
  COUNTER(override_dir_exists)                                                                     \
49
55.3k
  COUNTER(override_dir_not_exists)                                                                 \
50
55.3k
  GAUGE(admin_overrides_active, NeverImport)                                                       \
51
55.3k
  GAUGE(deprecated_feature_seen_since_process_start, NeverImport)                                  \
52
55.3k
  GAUGE(num_keys, NeverImport)                                                                     \
53
55.3k
  GAUGE(num_layers, NeverImport)
54
55
/**
56
 * Struct definition for all runtime stats. @see stats_macros.h
57
 */
58
struct RuntimeStats {
59
  ALL_RUNTIME_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT)
60
};
61
62
/**
63
 * Implementation of Snapshot whose source is the vector of layers passed to the constructor.
64
 */
65
class SnapshotImpl : public Snapshot, Logger::Loggable<Logger::Id::runtime> {
66
public:
67
  SnapshotImpl(Random::RandomGenerator& generator, RuntimeStats& stats,
68
               std::vector<OverrideLayerConstPtr>&& layers);
69
70
  // Runtime::Snapshot
71
  bool deprecatedFeatureEnabled(absl::string_view key, bool default_value) const override;
72
  bool runtimeFeatureEnabled(absl::string_view key) const override;
73
  bool featureEnabled(absl::string_view key, uint64_t default_value, uint64_t random_value,
74
                      uint64_t num_buckets) const override;
75
  bool featureEnabled(absl::string_view key, uint64_t default_value) const override;
76
  bool featureEnabled(absl::string_view key, uint64_t default_value,
77
                      uint64_t random_value) const override;
78
  bool featureEnabled(absl::string_view key,
79
                      const envoy::type::v3::FractionalPercent& default_value) const override;
80
  bool featureEnabled(absl::string_view key,
81
                      const envoy::type::v3::FractionalPercent& default_value,
82
                      uint64_t random_value) const override;
83
  ConstStringOptRef get(absl::string_view key) const override;
84
  uint64_t getInteger(absl::string_view key, uint64_t default_value) const override;
85
  double getDouble(absl::string_view key, double default_value) const override;
86
  bool getBoolean(absl::string_view key, bool value) const override;
87
  const std::vector<OverrideLayerConstPtr>& getLayers() const override;
88
89
  const EntryMap& values() const;
90
91
  static Entry createEntry(const ProtobufWkt::Value& value, absl::string_view raw_string,
92
                           const char*& error_message);
93
  static void addEntry(Snapshot::EntryMap& values, const std::string& key,
94
                       const ProtobufWkt::Value& value, absl::string_view raw_string = "");
95
96
private:
97
  const std::vector<OverrideLayerConstPtr> layers_;
98
  EntryMap values_;
99
  Random::RandomGenerator& generator_;
100
  RuntimeStats& stats_;
101
};
102
103
using SnapshotImplPtr = std::unique_ptr<SnapshotImpl>;
104
105
/**
106
 * Base implementation of OverrideLayer that by itself provides an empty values map.
107
 */
108
class OverrideLayerImpl : public Snapshot::OverrideLayer {
109
public:
110
154k
  explicit OverrideLayerImpl(absl::string_view name) : name_{name} {}
111
196k
  const Snapshot::EntryMap& values() const override { return values_; }
112
0
  const std::string& name() const override { return name_; }
113
114
protected:
115
  Snapshot::EntryMap values_;
116
  const std::string name_;
117
};
118
119
/**
120
 * Extension of OverrideLayerImpl that maintains an in-memory set of values. These values can be
121
 * modified programmatically via mergeValues(). AdminLayer is so named because it
122
 * can be accessed and manipulated by Envoy's admin interface.
123
 */
124
class AdminLayer : public OverrideLayerImpl {
125
public:
126
  explicit AdminLayer(absl::string_view name, RuntimeStats& stats)
127
148k
      : OverrideLayerImpl{name}, stats_{stats} {}
128
  /**
129
   * Copy-constructible so that it can snapshotted.
130
   */
131
95.5k
  AdminLayer(const AdminLayer& admin_layer) : AdminLayer{admin_layer.name_, admin_layer.stats_} {
132
95.5k
    values_ = admin_layer.values();
133
95.5k
  }
134
135
  /**
136
   * Merge the provided values into our entry map. An empty value indicates that a key should be
137
   * removed from our map.
138
   */
139
  absl::Status mergeValues(const absl::node_hash_map<std::string, std::string>& values);
140
141
private:
142
  RuntimeStats& stats_;
143
};
144
145
using AdminLayerPtr = std::unique_ptr<AdminLayer>;
146
147
/**
148
 * Extension of OverrideLayerImpl that loads values from the file system upon construction.
149
 */
150
class DiskLayer : public OverrideLayerImpl, Logger::Loggable<Logger::Id::runtime> {
151
public:
152
  DiskLayer(absl::string_view name, const std::string& path, Api::Api& api,
153
            absl::Status& creation_status);
154
155
private:
156
  absl::Status walkDirectory(const std::string& path, const std::string& prefix, uint32_t depth,
157
                             Api::Api& api);
158
159
  const std::string path_;
160
  const Filesystem::WatcherPtr watcher_;
161
};
162
163
/**
164
 * Extension of OverrideLayerImpl that loads values from a proto Struct representation.
165
 */
166
class ProtoLayer : public OverrideLayerImpl, Logger::Loggable<Logger::Id::runtime> {
167
public:
168
  ProtoLayer(absl::string_view name, const ProtobufWkt::Struct& proto,
169
             absl::Status& creation_status);
170
171
private:
172
  absl::Status walkProtoValue(const ProtobufWkt::Value& v, const std::string& prefix);
173
};
174
175
class LoaderImpl;
176
177
struct RtdsSubscription : Envoy::Config::SubscriptionBase<envoy::service::runtime::v3::Runtime>,
178
                          Logger::Loggable<Logger::Id::runtime> {
179
  RtdsSubscription(LoaderImpl& parent,
180
                   const envoy::config::bootstrap::v3::RuntimeLayer::RtdsLayer& rtds_layer,
181
                   Stats::Store& store, ProtobufMessage::ValidationVisitor& validation_visitor);
182
183
  // Config::SubscriptionCallbacks
184
  absl::Status onConfigUpdate(const std::vector<Config::DecodedResourceRef>& resources,
185
                              const std::string& version_info) override;
186
  absl::Status onConfigUpdate(const std::vector<Config::DecodedResourceRef>& added_resources,
187
                              const Protobuf::RepeatedPtrField<std::string>& removed_resources,
188
                              const std::string&) override;
189
190
  void onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason reason,
191
                            const EnvoyException* e) override;
192
193
  void start();
194
  absl::Status validateUpdateSize(uint32_t added_resources_num, uint32_t removed_resources_num);
195
  absl::Status onConfigRemoved(const Protobuf::RepeatedPtrField<std::string>& removed_resources);
196
  absl::Status createSubscription();
197
198
  LoaderImpl& parent_;
199
  const envoy::config::core::v3::ConfigSource config_source_;
200
  Stats::Store& store_;
201
  Stats::ScopeSharedPtr stats_scope_;
202
  Config::SubscriptionPtr subscription_;
203
  std::string resource_name_;
204
  Init::TargetImpl init_target_;
205
  ProtobufWkt::Struct proto_;
206
};
207
208
using RtdsSubscriptionPtr = std::unique_ptr<RtdsSubscription>;
209
210
/**
211
 * Implementation of Loader that provides Snapshots of values added via mergeValues().
212
 * A single snapshot is shared among all threads and referenced by shared_ptr such that
213
 * a new runtime can be swapped in by the main thread while workers are still using the previous
214
 * version.
215
 */
216
class LoaderImpl : public Loader, Logger::Loggable<Logger::Id::runtime> {
217
public:
218
  static absl::StatusOr<std::unique_ptr<LoaderImpl>>
219
  create(Event::Dispatcher& dispatcher, ThreadLocal::SlotAllocator& tls,
220
         const envoy::config::bootstrap::v3::LayeredRuntime& config,
221
         const LocalInfo::LocalInfo& local_info, Stats::Store& store,
222
         Random::RandomGenerator& generator, ProtobufMessage::ValidationVisitor& validation_visitor,
223
         Api::Api& api);
224
225
  // Runtime::Loader
226
  absl::Status initialize(Upstream::ClusterManager& cm) override;
227
  const Snapshot& snapshot() override;
228
  SnapshotConstSharedPtr threadsafeSnapshot() override;
229
  absl::Status mergeValues(const absl::node_hash_map<std::string, std::string>& values) override;
230
  void startRtdsSubscriptions(ReadyCallback on_done) override;
231
  Stats::Scope& getRootScope() override;
232
  void countDeprecatedFeatureUse() const override;
233
234
private:
235
  friend RtdsSubscription;
236
  LoaderImpl(ThreadLocal::SlotAllocator& tls,
237
             const envoy::config::bootstrap::v3::LayeredRuntime& config,
238
             const LocalInfo::LocalInfo& local_info, Stats::Store& store,
239
             Random::RandomGenerator& generator, Api::Api& api);
240
241
  absl::Status initLayers(Event::Dispatcher& dispatcher,
242
                          ProtobufMessage::ValidationVisitor& validation_visitor);
243
  // Create a new Snapshot
244
  absl::StatusOr<SnapshotImplPtr> createNewSnapshot();
245
  // Load a new Snapshot into TLS
246
  absl::Status loadNewSnapshot();
247
  RuntimeStats generateStats(Stats::Store& store);
248
  void onRtdsReady();
249
250
  Random::RandomGenerator& generator_;
251
  RuntimeStats stats_;
252
  AdminLayerPtr admin_layer_;
253
  ThreadLocal::SlotPtr tls_;
254
  const envoy::config::bootstrap::v3::LayeredRuntime config_;
255
  const std::string service_cluster_;
256
  Filesystem::WatcherPtr watcher_;
257
  Api::Api& api_;
258
  ReadyCallback on_rtds_initialized_;
259
  Init::WatcherImpl init_watcher_;
260
  Init::ManagerImpl init_manager_{"RTDS"};
261
  std::vector<RtdsSubscriptionPtr> subscriptions_;
262
  Upstream::ClusterManager* cm_{};
263
  Stats::Store& store_;
264
265
  absl::Mutex snapshot_mutex_;
266
  SnapshotConstSharedPtr thread_safe_snapshot_ ABSL_GUARDED_BY(snapshot_mutex_);
267
};
268
269
} // namespace Runtime
270
} // namespace Envoy