1
#include "source/server/configuration_impl.h"
2

            
3
#include <chrono>
4
#include <list>
5
#include <memory>
6
#include <string>
7
#include <vector>
8

            
9
#include "envoy/common/exception.h"
10
#include "envoy/config/bootstrap/v3/bootstrap.pb.h"
11
#include "envoy/config/metrics/v3/stats.pb.h"
12
#include "envoy/config/trace/v3/http_tracer.pb.h"
13
#include "envoy/extensions/access_loggers/file/v3/file.pb.h"
14
#include "envoy/network/connection.h"
15
#include "envoy/runtime/runtime.h"
16
#include "envoy/server/instance.h"
17
#include "envoy/server/tracer_config.h"
18
#include "envoy/ssl/context_manager.h"
19

            
20
#include "source/common/access_log/access_log_impl.h"
21
#include "source/common/common/assert.h"
22
#include "source/common/common/utility.h"
23
#include "source/common/config/runtime_utility.h"
24
#include "source/common/config/utility.h"
25
#include "source/common/network/socket_option_factory.h"
26
#include "source/common/protobuf/utility.h"
27

            
28
namespace Envoy {
29
namespace Server {
30
namespace Configuration {
31

            
32
bool FilterChainUtility::buildFilterChain(Network::FilterManager& filter_manager,
33
24578
                                          const Filter::NetworkFilterFactoriesList& factories) {
34
24784
  for (const auto& filter_config_provider : factories) {
35
24784
    auto config = filter_config_provider->config();
36
24784
    if (!config.has_value()) {
37
6
      return false;
38
6
    }
39

            
40
24778
    Network::FilterFactoryCb& factory = config.value();
41
24778
    factory(filter_manager);
42
24778
  }
43

            
44
24572
  return filter_manager.initializeReadFilters();
45
24578
}
46

            
47
bool FilterChainUtility::buildFilterChain(Network::ListenerFilterManager& filter_manager,
48
22587
                                          const Filter::ListenerFilterFactoriesList& factories) {
49
22616
  for (const auto& filter_config_provider : factories) {
50
300
    auto config = filter_config_provider->config();
51
300
    if (!config.has_value()) {
52
6
      return false;
53
6
    }
54
294
    auto config_value = config.value();
55
294
    config_value(filter_manager);
56
294
  }
57

            
58
22581
  return true;
59
22587
}
60

            
61
void FilterChainUtility::buildUdpFilterChain(
62
    Network::UdpListenerFilterManager& filter_manager, Network::UdpReadFilterCallbacks& callbacks,
63
138
    const std::vector<Network::UdpListenerFilterFactoryCb>& factories) {
64
143
  for (const Network::UdpListenerFilterFactoryCb& factory : factories) {
65
143
    factory(filter_manager, callbacks);
66
143
  }
67
138
}
68

            
69
bool FilterChainUtility::buildQuicFilterChain(
70
    Network::QuicListenerFilterManager& filter_manager,
71
1996
    const Filter::QuicListenerFilterFactoriesList& factories) {
72
1996
  for (const auto& filter_config_provider : factories) {
73
20
    auto config = filter_config_provider->config();
74
20
    if (!config.has_value()) {
75
2
      return false;
76
2
    }
77
18
    auto config_value = config.value();
78
18
    config_value(filter_manager);
79
18
  }
80

            
81
1994
  return true;
82
1996
}
83

            
84
StatsConfigImpl::StatsConfigImpl(const envoy::config::bootstrap::v3::Bootstrap& bootstrap,
85
                                 absl::Status& status)
86
10822
    : deferred_stat_options_(bootstrap.deferred_stat_options()) {
87
10822
  status = absl::OkStatus();
88
10822
  if (bootstrap.has_stats_flush_interval() &&
89
10822
      bootstrap.stats_flush_case() !=
90
24
          envoy::config::bootstrap::v3::Bootstrap::STATS_FLUSH_NOT_SET) {
91
1
    status = absl::InvalidArgumentError(
92
1
        "Only one of stats_flush_interval or stats_flush_on_admin should be set!");
93
1
    return;
94
1
  }
95

            
96
10821
  flush_interval_ =
97
10821
      std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(bootstrap, stats_flush_interval, 5000));
98

            
99
10821
  if (bootstrap.stats_flush_case() == envoy::config::bootstrap::v3::Bootstrap::kStatsFlushOnAdmin) {
100
3
    flush_on_admin_ = bootstrap.stats_flush_on_admin();
101
3
  }
102

            
103
10821
  const auto evict_interval_ms = PROTOBUF_GET_MS_OR_DEFAULT(bootstrap, stats_eviction_interval, 0);
104
10821
  if (evict_interval_ms % flush_interval_.count() != 0) {
105
1
    status = absl::InvalidArgumentError(
106
1
        "stats_eviction_interval must be a multiple of stats_flush_interval");
107
1
    return;
108
1
  }
109
10820
  evict_on_flush_ = evict_interval_ms / flush_interval_.count();
110
10820
}
111

            
112
absl::Status MainImpl::initialize(const envoy::config::bootstrap::v3::Bootstrap& bootstrap,
113
                                  Instance& server,
114
10823
                                  Upstream::ClusterManagerFactory& cluster_manager_factory) {
115
  // In order to support dynamic configuration of tracing providers,
116
  // a former server-wide Tracer singleton has been replaced by
117
  // an Tracer instance per "envoy.filters.network.http_connection_manager" filter.
118
  // Tracing configuration as part of bootstrap config is still supported,
119
  // however, it's become mandatory to process it prior to static Listeners.
120
  // Otherwise, static Listeners will be configured in assumption that
121
  // tracing configuration is missing from the bootstrap config.
122
10823
  initializeTracers(bootstrap.tracing(), server);
123

            
124
  // stats_config_ should be set before creating the ClusterManagers so that it is available
125
  // from the ServerFactoryContext when creating the static clusters and stats sinks, where
126
  // stats deferred instantiation setting is read.
127
10823
  absl::Status status = absl::OkStatus();
128
10823
  stats_config_ = std::make_unique<StatsConfigImpl>(bootstrap, status);
129
10823
  RETURN_IF_NOT_OK(status);
130

            
131
10821
  const auto& secrets = bootstrap.static_resources().secrets();
132
10821
  ENVOY_LOG(info, "loading {} static secret(s)", secrets.size());
133
19583
  for (ssize_t i = 0; i < secrets.size(); i++) {
134
8762
    ENVOY_LOG(debug, "static secret #{}: {}", i, secrets[i].name());
135
8762
    RETURN_IF_NOT_OK(server.secretManager().addStaticSecret(secrets[i]));
136
8762
  }
137

            
138
10821
  ENVOY_LOG(info, "loading {} cluster(s)", bootstrap.static_resources().clusters().size());
139

            
140
  // clusterManagerFromProto() and init() have to be called consecutively.
141
10821
  auto manager_or_error = cluster_manager_factory.clusterManagerFromProto(bootstrap);
142
10821
  RETURN_IF_NOT_OK_REF(manager_or_error.status());
143
10821
  cluster_manager_ = std::move(*manager_or_error);
144
10821
  status = cluster_manager_->initialize(bootstrap);
145
10821
  RETURN_IF_NOT_OK(status);
146

            
147
10819
  const auto& listeners = bootstrap.static_resources().listeners();
148
10819
  ENVOY_LOG(info, "loading {} listener(s)", listeners.size());
149
11263
  for (ssize_t i = 0; i < listeners.size(); i++) {
150
449
    ENVOY_LOG(debug, "listener #{}:", i);
151
449
    absl::StatusOr<bool> update_or_error =
152
449
        server.listenerManager().addOrUpdateListener(listeners[i], "", false);
153
449
    RETURN_IF_NOT_OK_REF(update_or_error.status());
154
444
  }
155
10814
  RETURN_IF_NOT_OK(initializeWatchdogs(bootstrap, server));
156
  // This has to happen after ClusterManager initialization, as it depends on config from
157
  // ClusterManager.
158
10813
  return initializeStatsConfig(bootstrap, server);
159
10814
}
160

            
161
absl::Status
162
MainImpl::initializeStatsConfig(const envoy::config::bootstrap::v3::Bootstrap& bootstrap,
163
10810
                                Instance& server) {
164
10810
  ENVOY_LOG(info, "loading stats configuration");
165

            
166
10810
  for (const envoy::config::metrics::v3::StatsSink& sink_object : bootstrap.stats_sinks()) {
167
    // Generate factory and translate stats sink custom config.
168
30
    auto& factory = Config::Utility::getAndCheckFactory<StatsSinkFactory>(sink_object);
169
30
    ProtobufTypes::MessagePtr message = Config::Utility::translateToFactoryConfig(
170
30
        sink_object, server.messageValidationContext().staticValidationVisitor(), factory);
171

            
172
30
    auto sink = factory.createStatsSink(*message, server.serverFactoryContext());
173
30
    RETURN_IF_NOT_OK_REF(sink.status());
174
30
    stats_config_->addSink(std::move(sink.value()));
175
30
  }
176
10810
  return absl::OkStatus();
177
10810
}
178

            
179
void MainImpl::initializeTracers(const envoy::config::trace::v3::Tracing& configuration,
180
10823
                                 Instance& server) {
181
10823
  ENVOY_LOG(info, "loading tracing configuration");
182

            
183
  // Default tracing configuration must be set prior to processing of static Listeners begins.
184
10823
  server.setDefaultTracingConfig(configuration);
185

            
186
10823
  if (!configuration.has_http()) {
187
10822
    return;
188
10822
  }
189

            
190
  // Validating tracing configuration (minimally).
191
1
  ENVOY_LOG(info, "  validating default server-wide tracing driver: {}",
192
1
            configuration.http().name());
193

            
194
  // Now see if there is a factory that will accept the config.
195
1
  auto& factory = Config::Utility::getAndCheckFactory<TracerFactory>(configuration.http());
196
1
  ProtobufTypes::MessagePtr message = Config::Utility::translateToFactoryConfig(
197
1
      configuration.http(), server.messageValidationContext().staticValidationVisitor(), factory);
198

            
199
  // Notice that the actual Tracer instance will be created on demand
200
  // in the context of "envoy.filters.network.http_connection_manager" filter.
201
  // The side effect of this is that provider-specific configuration
202
  // is no longer validated in this step.
203
1
}
204

            
205
absl::Status MainImpl::initializeWatchdogs(const envoy::config::bootstrap::v3::Bootstrap& bootstrap,
206
10811
                                           Instance& server) {
207
10811
  if (bootstrap.has_watchdog() && bootstrap.has_watchdogs()) {
208
1
    return absl::InvalidArgumentError("Only one of watchdog or watchdogs should be set!");
209
1
  }
210

            
211
10810
  if (bootstrap.has_watchdog()) {
212
3
    main_thread_watchdog_ = std::make_unique<WatchdogImpl>(bootstrap.watchdog(), server);
213
3
    worker_watchdog_ = std::make_unique<WatchdogImpl>(bootstrap.watchdog(), server);
214
10807
  } else {
215
10807
    main_thread_watchdog_ =
216
10807
        std::make_unique<WatchdogImpl>(bootstrap.watchdogs().main_thread_watchdog(), server);
217
10807
    worker_watchdog_ =
218
10807
        std::make_unique<WatchdogImpl>(bootstrap.watchdogs().worker_watchdog(), server);
219
10807
  }
220
10810
  return absl::OkStatus();
221
10811
}
222

            
223
WatchdogImpl::WatchdogImpl(const envoy::config::bootstrap::v3::Watchdog& watchdog,
224
21620
                           Instance& server) {
225
21620
  miss_timeout_ =
226
21620
      std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(watchdog, miss_timeout, 200));
227
21620
  megamiss_timeout_ =
228
21620
      std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(watchdog, megamiss_timeout, 1000));
229

            
230
21620
  uint64_t kill_timeout = PROTOBUF_GET_MS_OR_DEFAULT(watchdog, kill_timeout, 0);
231
21620
  const uint64_t max_kill_timeout_jitter =
232
21620
      PROTOBUF_GET_MS_OR_DEFAULT(watchdog, max_kill_timeout_jitter, 0);
233

            
234
  // Adjust kill timeout if we have skew enabled.
235
21620
  if (kill_timeout > 0 && max_kill_timeout_jitter > 0) {
236
    // Increments the kill timeout with a random value in (0, max_skew].
237
    // We shouldn't have overflow issues due to the range of Duration.
238
    // This won't be entirely uniform, depending on how large max_skew
239
    // is relation to uint64.
240
2
    kill_timeout += (server.api().randomGenerator().random() % max_kill_timeout_jitter) + 1;
241
2
  }
242

            
243
21620
  kill_timeout_ = std::chrono::milliseconds(kill_timeout);
244
21620
  multikill_timeout_ =
245
21620
      std::chrono::milliseconds(PROTOBUF_GET_MS_OR_DEFAULT(watchdog, multikill_timeout, 0));
246
21620
  multikill_threshold_ = PROTOBUF_PERCENT_TO_DOUBLE_OR_DEFAULT(watchdog, multikill_threshold, 0.0);
247
21620
  actions_ = watchdog.actions();
248
21620
}
249

            
250
InitialImpl::InitialImpl(const envoy::config::bootstrap::v3::Bootstrap& bootstrap,
251
10815
                         absl::Status& creation_status) {
252
10815
  creation_status = absl::OkStatus();
253
10815
  const auto& admin = bootstrap.admin();
254

            
255
10815
  admin_.profile_path_ =
256
10815
      admin.profile_path().empty() ? "/var/log/envoy/envoy.prof" : admin.profile_path();
257
10815
  if (admin.has_address()) {
258
10742
    auto address_or_error = Network::Address::resolveProtoAddress(admin.address());
259
10742
    if (!address_or_error.status().ok()) {
260
      creation_status = address_or_error.status();
261
      return;
262
    }
263
10742
    admin_.address_ = std::move(address_or_error.value());
264
10742
  }
265
10815
  admin_.socket_options_ = std::make_shared<std::vector<Network::Socket::OptionConstSharedPtr>>();
266
10815
  if (!admin.socket_options().empty()) {
267
2
    Network::Socket::appendOptions(
268
2
        admin_.socket_options_,
269
2
        Network::SocketOptionFactory::buildLiteralOptions(admin.socket_options()));
270
2
  }
271
10815
  admin_.ignore_global_conn_limit_ = admin.ignore_global_conn_limit();
272

            
273
10815
  if (!bootstrap.flags_path().empty()) {
274
6
    flags_path_ = bootstrap.flags_path();
275
6
  }
276

            
277
10815
  if (bootstrap.has_layered_runtime()) {
278
10559
    layered_runtime_.MergeFrom(bootstrap.layered_runtime());
279
10559
    if (layered_runtime_.layers().empty()) {
280
1
      layered_runtime_.add_layers()->mutable_admin_layer();
281
1
    }
282
10559
  }
283
10815
}
284

            
285
void InitialImpl::initAdminAccessLog(const envoy::config::bootstrap::v3::Bootstrap& bootstrap,
286
10689
                                     FactoryContext& factory_context) {
287
10689
  const auto& admin = bootstrap.admin();
288

            
289
10689
  for (const auto& access_log : admin.access_log()) {
290
10619
    AccessLog::InstanceSharedPtr current_access_log =
291
10619
        AccessLog::AccessLogFactory::fromProto(access_log, factory_context);
292
10619
    admin_.access_logs_.emplace_back(current_access_log);
293
10619
  }
294

            
295
10689
  if (!admin.access_log_path().empty()) {
296
3
    envoy::extensions::access_loggers::file::v3::FileAccessLog config;
297
3
    config.mutable_format();
298
3
    config.set_path(admin.access_log_path());
299

            
300
3
    auto factory = Config::Utility::getFactoryByName<AccessLog::AccessLogInstanceFactory>(
301
3
        "envoy.file_access_log");
302
3
    admin_.access_logs_.emplace_back(factory->createAccessLogInstance(config, {}, factory_context));
303
3
  }
304
10689
}
305

            
306
} // namespace Configuration
307
} // namespace Server
308
} // namespace Envoy