Line data Source code
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 "spdlog/spdlog.h"
34 :
35 : namespace Envoy {
36 : namespace Runtime {
37 :
38 : using RuntimeSingleton = ThreadSafeSingleton<Loader>;
39 :
40 : /**
41 : * All runtime stats. @see stats_macros.h
42 : */
43 : #define ALL_RUNTIME_STATS(COUNTER, GAUGE) \
44 1145 : COUNTER(deprecated_feature_use) \
45 1145 : COUNTER(load_error) \
46 1145 : COUNTER(load_success) \
47 1145 : COUNTER(override_dir_exists) \
48 1145 : COUNTER(override_dir_not_exists) \
49 1145 : GAUGE(admin_overrides_active, NeverImport) \
50 1145 : GAUGE(deprecated_feature_seen_since_process_start, NeverImport) \
51 1145 : GAUGE(num_keys, NeverImport) \
52 1145 : GAUGE(num_layers, NeverImport)
53 :
54 : /**
55 : * Struct definition for all runtime stats. @see stats_macros.h
56 : */
57 : struct RuntimeStats {
58 : ALL_RUNTIME_STATS(GENERATE_COUNTER_STRUCT, GENERATE_GAUGE_STRUCT)
59 : };
60 :
61 : /**
62 : * Implementation of Snapshot whose source is the vector of layers passed to the constructor.
63 : */
64 : class SnapshotImpl : public Snapshot, Logger::Loggable<Logger::Id::runtime> {
65 : public:
66 : SnapshotImpl(Random::RandomGenerator& generator, RuntimeStats& stats,
67 : std::vector<OverrideLayerConstPtr>&& layers);
68 :
69 : // Runtime::Snapshot
70 : bool deprecatedFeatureEnabled(absl::string_view key, bool default_value) const override;
71 : bool runtimeFeatureEnabled(absl::string_view key) const override;
72 : bool featureEnabled(absl::string_view key, uint64_t default_value, uint64_t random_value,
73 : uint64_t num_buckets) const override;
74 : bool featureEnabled(absl::string_view key, uint64_t default_value) const override;
75 : bool featureEnabled(absl::string_view key, uint64_t default_value,
76 : uint64_t random_value) const override;
77 : bool featureEnabled(absl::string_view key,
78 : const envoy::type::v3::FractionalPercent& default_value) const override;
79 : bool featureEnabled(absl::string_view key,
80 : const envoy::type::v3::FractionalPercent& default_value,
81 : uint64_t random_value) const override;
82 : ConstStringOptRef get(absl::string_view key) const override;
83 : uint64_t getInteger(absl::string_view key, uint64_t default_value) const override;
84 : double getDouble(absl::string_view key, double default_value) const override;
85 : bool getBoolean(absl::string_view key, bool value) const override;
86 : const std::vector<OverrideLayerConstPtr>& getLayers() const override;
87 :
88 : const EntryMap& values() const;
89 :
90 : static Entry createEntry(const ProtobufWkt::Value& value, absl::string_view raw_string,
91 : const char*& error_message);
92 : static void addEntry(Snapshot::EntryMap& values, const std::string& key,
93 : const ProtobufWkt::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 2879 : explicit OverrideLayerImpl(absl::string_view name) : name_{name} {}
110 3435 : const Snapshot::EntryMap& values() const override { return values_; }
111 0 : 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 can be accessed
121 : * 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 2780 : : OverrideLayerImpl{name}, stats_{stats} {}
127 : /**
128 : * Copy-constructible so that it can snapshotted.
129 : */
130 1668 : AdminLayer(const AdminLayer& admin_layer) : AdminLayer{admin_layer.name_, admin_layer.stats_} {
131 1668 : values_ = admin_layer.values();
132 1668 : }
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 : void 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 :
153 : private:
154 : void walkDirectory(const std::string& path, const std::string& prefix, uint32_t depth,
155 : Api::Api& api);
156 :
157 : const std::string path_;
158 : const Filesystem::WatcherPtr watcher_;
159 : };
160 :
161 : /**
162 : * Extension of OverrideLayerImpl that loads values from a proto Struct representation.
163 : */
164 : class ProtoLayer : public OverrideLayerImpl, Logger::Loggable<Logger::Id::runtime> {
165 : public:
166 : ProtoLayer(absl::string_view name, const ProtobufWkt::Struct& proto);
167 :
168 : private:
169 : void walkProtoValue(const ProtobufWkt::Value& v, const std::string& prefix);
170 : };
171 :
172 : class LoaderImpl;
173 :
174 : struct RtdsSubscription : Envoy::Config::SubscriptionBase<envoy::service::runtime::v3::Runtime>,
175 : Logger::Loggable<Logger::Id::runtime> {
176 : RtdsSubscription(LoaderImpl& parent,
177 : const envoy::config::bootstrap::v3::RuntimeLayer::RtdsLayer& rtds_layer,
178 : Stats::Store& store, ProtobufMessage::ValidationVisitor& validation_visitor);
179 :
180 : // Config::SubscriptionCallbacks
181 : absl::Status onConfigUpdate(const std::vector<Config::DecodedResourceRef>& resources,
182 : const std::string& version_info) override;
183 : absl::Status onConfigUpdate(const std::vector<Config::DecodedResourceRef>& added_resources,
184 : const Protobuf::RepeatedPtrField<std::string>& removed_resources,
185 : const std::string&) override;
186 :
187 : void onConfigUpdateFailed(Envoy::Config::ConfigUpdateFailureReason reason,
188 : const EnvoyException* e) override;
189 :
190 : void start();
191 : absl::Status validateUpdateSize(uint32_t added_resources_num, uint32_t removed_resources_num);
192 : absl::Status onConfigRemoved(const Protobuf::RepeatedPtrField<std::string>& removed_resources);
193 : void createSubscription();
194 :
195 : LoaderImpl& parent_;
196 : const envoy::config::core::v3::ConfigSource config_source_;
197 : Stats::Store& store_;
198 : Stats::ScopeSharedPtr stats_scope_;
199 : Config::SubscriptionPtr subscription_;
200 : std::string resource_name_;
201 : Init::TargetImpl init_target_;
202 : ProtobufWkt::Struct proto_;
203 : };
204 :
205 : using RtdsSubscriptionPtr = std::unique_ptr<RtdsSubscription>;
206 :
207 : /**
208 : * Implementation of Loader that provides Snapshots of values added via mergeValues().
209 : * A single snapshot is shared among all threads and referenced by shared_ptr such that
210 : * a new runtime can be swapped in by the main thread while workers are still using the previous
211 : * version.
212 : */
213 : class LoaderImpl : public Loader, Logger::Loggable<Logger::Id::runtime> {
214 : public:
215 : LoaderImpl(Event::Dispatcher& dispatcher, ThreadLocal::SlotAllocator& tls,
216 : const envoy::config::bootstrap::v3::LayeredRuntime& config,
217 : const LocalInfo::LocalInfo& local_info, Stats::Store& store,
218 : Random::RandomGenerator& generator,
219 : ProtobufMessage::ValidationVisitor& validation_visitor, Api::Api& api);
220 :
221 : // Runtime::Loader
222 : void initialize(Upstream::ClusterManager& cm) override;
223 : const Snapshot& snapshot() override;
224 : SnapshotConstSharedPtr threadsafeSnapshot() override;
225 : void mergeValues(const absl::node_hash_map<std::string, std::string>& values) override;
226 : void startRtdsSubscriptions(ReadyCallback on_done) override;
227 : Stats::Scope& getRootScope() override;
228 : void countDeprecatedFeatureUse() const override;
229 :
230 : private:
231 : friend RtdsSubscription;
232 :
233 : // Create a new Snapshot
234 : SnapshotImplPtr createNewSnapshot();
235 : // Load a new Snapshot into TLS
236 : void loadNewSnapshot();
237 : RuntimeStats generateStats(Stats::Store& store);
238 : void onRtdsReady();
239 :
240 : Random::RandomGenerator& generator_;
241 : RuntimeStats stats_;
242 : AdminLayerPtr admin_layer_;
243 : ThreadLocal::SlotPtr tls_;
244 : const envoy::config::bootstrap::v3::LayeredRuntime config_;
245 : const std::string service_cluster_;
246 : Filesystem::WatcherPtr watcher_;
247 : Api::Api& api_;
248 : ReadyCallback on_rtds_initialized_;
249 : Init::WatcherImpl init_watcher_;
250 : Init::ManagerImpl init_manager_{"RTDS"};
251 : std::vector<RtdsSubscriptionPtr> subscriptions_;
252 : Upstream::ClusterManager* cm_{};
253 : Stats::Store& store_;
254 :
255 : absl::Mutex snapshot_mutex_;
256 : SnapshotConstSharedPtr thread_safe_snapshot_ ABSL_GUARDED_BY(snapshot_mutex_);
257 : };
258 :
259 : } // namespace Runtime
260 : } // namespace Envoy
|