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
14231
  COUNTER(deprecated_feature_use)                                                                  \
46
14231
  COUNTER(load_error)                                                                              \
47
14231
  COUNTER(load_success)                                                                            \
48
14231
  COUNTER(override_dir_exists)                                                                     \
49
14231
  COUNTER(override_dir_not_exists)                                                                 \
50
14231
  GAUGE(admin_overrides_active, NeverImport)                                                       \
51
14231
  GAUGE(deprecated_feature_seen_since_process_start, NeverImport)                                  \
52
14231
  GAUGE(num_keys, NeverImport)                                                                     \
53
14231
  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 Protobuf::Value& value, absl::string_view raw_string);
92
  static void addEntry(Snapshot::EntryMap& values, const std::string& key,
93
                       const Protobuf::Value& value, absl::string_view raw_string = "");
94

            
95
private:
96
  const std::vector<OverrideLayerConstPtr> layers_;
97
  EntryMap values_;
98
  Random::RandomGenerator& generator_;
99
  RuntimeStats& stats_;
100
};
101

            
102
using SnapshotImplPtr = std::unique_ptr<SnapshotImpl>;
103

            
104
/**
105
 * Base implementation of OverrideLayer that by itself provides an empty values map.
106
 */
107
class OverrideLayerImpl : public Snapshot::OverrideLayer {
108
public:
109
42367
  explicit OverrideLayerImpl(absl::string_view name) : name_{name} {}
110
49302
  const Snapshot::EntryMap& values() const override { return values_; }
111
351
  const std::string& name() const override { return name_; }
112

            
113
protected:
114
  Snapshot::EntryMap values_;
115
  const std::string name_;
116
};
117

            
118
/**
119
 * Extension of OverrideLayerImpl that maintains an in-memory set of values. These values can be
120
 * modified programmatically via mergeValues(). AdminLayer is so named because it
121
 * can be accessed and manipulated by Envoy's admin interface.
122
 */
123
class AdminLayer : public OverrideLayerImpl {
124
public:
125
  explicit AdminLayer(absl::string_view name, RuntimeStats& stats)
126
31522
      : OverrideLayerImpl{name}, stats_{stats} {}
127
  /**
128
   * Copy-constructible so that it can snapshotted.
129
   */
130
17490
  AdminLayer(const AdminLayer& admin_layer) : AdminLayer{admin_layer.name_, admin_layer.stats_} {
131
17490
    values_ = admin_layer.values();
132
17490
  }
133

            
134
  /**
135
   * Merge the provided values into our entry map. An empty value indicates that a key should be
136
   * removed from our map.
137
   */
138
  absl::Status mergeValues(const absl::node_hash_map<std::string, std::string>& values);
139

            
140
private:
141
  RuntimeStats& stats_;
142
};
143

            
144
using AdminLayerPtr = std::unique_ptr<AdminLayer>;
145

            
146
/**
147
 * Extension of OverrideLayerImpl that loads values from the file system upon construction.
148
 */
149
class DiskLayer : public OverrideLayerImpl, Logger::Loggable<Logger::Id::runtime> {
150
public:
151
  DiskLayer(absl::string_view name, const std::string& path, Api::Api& api,
152
            absl::Status& creation_status);
153

            
154
private:
155
  absl::Status walkDirectory(const std::string& path, const std::string& prefix, uint32_t depth,
156
                             Api::Api& api);
157

            
158
  const std::string path_;
159
  const Filesystem::WatcherPtr watcher_;
160
};
161

            
162
/**
163
 * Extension of OverrideLayerImpl that loads values from a proto Struct representation.
164
 */
165
class ProtoLayer : public OverrideLayerImpl, Logger::Loggable<Logger::Id::runtime> {
166
public:
167
  ProtoLayer(absl::string_view name, const Protobuf::Struct& proto, absl::Status& creation_status);
168

            
169
private:
170
  absl::Status walkProtoValue(const Protobuf::Value& v, const std::string& prefix);
171
};
172

            
173
class LoaderImpl;
174

            
175
struct RtdsSubscription : Envoy::Config::SubscriptionBase<envoy::service::runtime::v3::Runtime>,
176
                          Logger::Loggable<Logger::Id::runtime> {
177
  RtdsSubscription(LoaderImpl& parent,
178
                   const envoy::config::bootstrap::v3::RuntimeLayer::RtdsLayer& rtds_layer,
179
                   Stats::Store& store, ProtobufMessage::ValidationVisitor& validation_visitor);
180

            
181
  // Config::SubscriptionCallbacks
182
  absl::Status onConfigUpdate(const std::vector<Config::DecodedResourceRef>& resources,
183
                              const std::string& version_info) override;
184
  absl::Status onConfigUpdate(const std::vector<Config::DecodedResourceRef>& added_resources,
185
                              const Protobuf::RepeatedPtrField<std::string>& removed_resources,
186
                              const std::string&) override;
187

            
188
  void onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason reason,
189
                            const EnvoyException* e) override;
190

            
191
  void start();
192
  absl::Status validateUpdateSize(uint32_t added_resources_num, uint32_t removed_resources_num);
193
  absl::Status onConfigRemoved(const Protobuf::RepeatedPtrField<std::string>& removed_resources);
194
  absl::Status createSubscription();
195

            
196
  LoaderImpl& parent_;
197
  const envoy::config::core::v3::ConfigSource config_source_;
198
  Stats::Store& store_;
199
  Stats::ScopeSharedPtr stats_scope_;
200
  Config::SubscriptionPtr subscription_;
201
  std::string resource_name_;
202
  Init::TargetImpl init_target_;
203
  Protobuf::Struct proto_;
204
};
205

            
206
using RtdsSubscriptionPtr = std::unique_ptr<RtdsSubscription>;
207

            
208
/**
209
 * Implementation of Loader that provides Snapshots of values added via mergeValues().
210
 * A single snapshot is shared among all threads and referenced by shared_ptr such that
211
 * a new runtime can be swapped in by the main thread while workers are still using the previous
212
 * version.
213
 */
214
class LoaderImpl : public Loader, Logger::Loggable<Logger::Id::runtime> {
215
public:
216
  static absl::StatusOr<std::unique_ptr<LoaderImpl>>
217
  create(Event::Dispatcher& dispatcher, ThreadLocal::SlotAllocator& tls,
218
         const envoy::config::bootstrap::v3::LayeredRuntime& config,
219
         const LocalInfo::LocalInfo& local_info, Stats::Store& store,
220
         Random::RandomGenerator& generator, ProtobufMessage::ValidationVisitor& validation_visitor,
221
         Api::Api& api);
222

            
223
  // Runtime::Loader
224
  absl::Status initialize(Upstream::ClusterManager& cm) override;
225
  const Snapshot& snapshot() const override;
226
  SnapshotConstSharedPtr threadsafeSnapshot() override;
227
  absl::Status mergeValues(const absl::node_hash_map<std::string, std::string>& values) override;
228
  void startRtdsSubscriptions(ReadyCallback on_done) override;
229
  Stats::Scope& getRootScope() override;
230
  void countDeprecatedFeatureUse() const override;
231

            
232
private:
233
  friend RtdsSubscription;
234
  LoaderImpl(ThreadLocal::SlotAllocator& tls,
235
             const envoy::config::bootstrap::v3::LayeredRuntime& config,
236
             const LocalInfo::LocalInfo& local_info, Stats::Store& store,
237
             Random::RandomGenerator& generator, Api::Api& api);
238

            
239
  absl::Status initLayers(Event::Dispatcher& dispatcher,
240
                          ProtobufMessage::ValidationVisitor& validation_visitor);
241
  // Create a new Snapshot
242
  absl::StatusOr<SnapshotImplPtr> createNewSnapshot();
243
  // Load a new Snapshot into TLS
244
  absl::Status loadNewSnapshot();
245
  RuntimeStats generateStats(Stats::Store& store);
246
  void onRtdsReady();
247

            
248
  Random::RandomGenerator& generator_;
249
  RuntimeStats stats_;
250
  AdminLayerPtr admin_layer_;
251
  ThreadLocal::SlotPtr tls_;
252
  const envoy::config::bootstrap::v3::LayeredRuntime config_;
253
  const std::string service_cluster_;
254
  Filesystem::WatcherPtr watcher_;
255
  Api::Api& api_;
256
  ReadyCallback on_rtds_initialized_;
257
  Init::WatcherImpl init_watcher_;
258
  Init::ManagerImpl init_manager_{"RTDS"};
259
  std::vector<RtdsSubscriptionPtr> subscriptions_;
260
  Upstream::ClusterManager* cm_{};
261
  Stats::Store& store_;
262

            
263
  absl::Mutex snapshot_mutex_;
264
  SnapshotConstSharedPtr thread_safe_snapshot_ ABSL_GUARDED_BY(snapshot_mutex_);
265
};
266

            
267
} // namespace Runtime
268
} // namespace Envoy