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

            
3
#include <memory>
4

            
5
#include "envoy/config/bootstrap/v3/bootstrap.pb.h"
6

            
7
#include "source/common/common/utility.h"
8
#include "source/common/config/utility.h"
9
#include "source/common/config/well_known_names.h"
10
#include "source/common/event/real_time_system.h"
11
#include "source/common/listener_manager/listener_info_impl.h"
12
#include "source/common/local_info/local_info_impl.h"
13
#include "source/common/protobuf/utility.h"
14
#include "source/common/stats/tag_producer_impl.h"
15
#include "source/common/tls/context_manager_impl.h"
16
#include "source/common/version/version.h"
17
#include "source/server/admin/admin_factory_context.h"
18
#include "source/server/listener_manager_factory.h"
19
#include "source/server/null_overload_manager.h"
20
#include "source/server/overload_manager_impl.h"
21
#include "source/server/regex_engine.h"
22
#include "source/server/utils.h"
23

            
24
namespace Envoy {
25
namespace Server {
26

            
27
bool validateConfig(const Options& options,
28
                    const Network::Address::InstanceConstSharedPtr& local_address,
29
                    ComponentFactory& component_factory, Thread::ThreadFactory& thread_factory,
30
                    Filesystem::Instance& file_system,
31
52
                    const ProcessContextOptRef& process_context) {
32
52
  Thread::MutexBasicLockable access_log_lock;
33
52
  Stats::IsolatedStoreImpl stats_store;
34

            
35
52
  TRY_ASSERT_MAIN_THREAD {
36
52
    Event::RealTimeSystem time_system;
37
52
    ValidationInstance server(options, time_system, local_address, stats_store, access_log_lock,
38
52
                              component_factory, thread_factory, file_system, process_context);
39
52
    std::cout << "configuration '" << options.configPath() << "' OK" << std::endl;
40
52
    server.shutdown();
41
52
    return true;
42
52
  }
43
52
  END_TRY
44
52
  catch (const EnvoyException& e) {
45
28
    return false;
46
28
  }
47
52
}
48

            
49
ValidationInstance::ValidationInstance(
50
    const Options& options, Event::TimeSystem& time_system,
51
    const Network::Address::InstanceConstSharedPtr& local_address, Stats::IsolatedStoreImpl& store,
52
    Thread::BasicLockable& access_log_lock, ComponentFactory& component_factory,
53
    Thread::ThreadFactory& thread_factory, Filesystem::Instance& file_system,
54
    const ProcessContextOptRef& process_context)
55
75
    : options_(options),
56
75
      validation_context_(options_.allowUnknownStaticFields(),
57
75
                          !options.rejectUnknownDynamicFields(),
58
75
                          !options.ignoreUnknownDynamicFields(), options.skipDeprecatedLogs()),
59
75
      stats_store_(store),
60
75
      api_(new Api::ValidationImpl(thread_factory, store, time_system, file_system,
61
75
                                   random_generator_, bootstrap_, process_context)),
62
75
      dispatcher_(api_->allocateDispatcher("main_thread")),
63
75
      access_log_manager_(options.fileFlushIntervalMsec(), options.fileFlushMinSizeKB(), *api_,
64
75
                          *dispatcher_, access_log_lock, store),
65
75
      grpc_context_(stats_store_.symbolTable()), http_context_(stats_store_.symbolTable()),
66
75
      router_context_(stats_store_.symbolTable()), time_system_(time_system),
67
75
      server_contexts_(*this), quic_stat_names_(stats_store_.symbolTable()) {
68

            
69
  // Register the server factory context on the main thread.
70
75
  Configuration::ServerFactoryContextInstance::initialize(&server_contexts_);
71

            
72
75
  TRY_ASSERT_MAIN_THREAD { initialize(options, local_address, component_factory); }
73
75
  END_TRY
74
75
  catch (const EnvoyException& e) {
75
31
    ENVOY_LOG(critical, "error initializing configuration '{}': {}", options.configPath(),
76
31
              e.what());
77
31
    shutdown();
78

            
79
    // Clear the server factory context on the main thread.
80
31
    Configuration::ServerFactoryContextInstance::clear();
81
31
    throw;
82
31
  }
83
75
}
84

            
85
44
ValidationInstance::~ValidationInstance() {
86
  // Clear the server factory context on the main thread.
87
44
  Configuration::ServerFactoryContextInstance::clear();
88
44
}
89

            
90
void ValidationInstance::initialize(const Options& options,
91
                                    const Network::Address::InstanceConstSharedPtr& local_address,
92
75
                                    ComponentFactory& component_factory) {
93
  // See comments on InstanceImpl::initialize() for the overall flow here.
94
  //
95
  // For validation, we only do a subset of normal server initialization: everything that could fail
96
  // on a malformed config (e.g. JSON parsing and all the object construction that follows), but
97
  // more importantly nothing with observable effects (e.g. binding to ports or shutting down any
98
  // other Envoy process).
99
  //
100
  // If we get all the way through that stripped-down initialization flow, to the point where we'd
101
  // be ready to serve, then the config has passed validation.
102
  // Handle configuration that needs to take place prior to the main configuration load.
103
75
  THROW_IF_NOT_OK(InstanceUtil::loadBootstrapConfig(
104
75
      bootstrap_, options, messageValidationContext().staticValidationVisitor(), *api_));
105

            
106
75
  if (bootstrap_.has_application_log_config()) {
107
5
    THROW_IF_NOT_OK(
108
5
        Utility::assertExclusiveLogFormatMethod(options_, bootstrap_.application_log_config()));
109
4
    THROW_IF_NOT_OK(Utility::maybeSetApplicationLogFormat(bootstrap_.application_log_config()));
110
4
  }
111

            
112
  // Inject regex engine to singleton.
113
72
  regex_engine_ = createRegexEngine(
114
72
      bootstrap_, messageValidationContext().staticValidationVisitor(), serverFactoryContext());
115

            
116
72
  auto producer_or_error =
117
72
      Stats::TagProducerImpl::createTagProducer(bootstrap_.stats_config(), options_.statsTags());
118
72
  THROW_IF_NOT_OK_REF(producer_or_error.status());
119
72
  if (!bootstrap_.node().user_agent_build_version().has_version()) {
120
49
    *bootstrap_.mutable_node()->mutable_user_agent_build_version() = VersionInfo::buildVersion();
121
49
  }
122

            
123
72
  local_info_ = std::make_unique<LocalInfo::LocalInfoImpl>(
124
72
      stats().symbolTable(), bootstrap_.node(), bootstrap_.node_context_params(), local_address,
125
72
      options.serviceZone(), options.serviceClusterName(), options.serviceNodeName());
126

            
127
72
  overload_manager_ = THROW_OR_RETURN_VALUE(
128
72
      OverloadManagerImpl::create(
129
72
          dispatcher(), *stats().rootScope(), threadLocal(), bootstrap_.overload_manager(),
130
72
          messageValidationContext().staticValidationVisitor(), *api_, options_),
131
72
      std::unique_ptr<OverloadManagerImpl>);
132
72
  null_overload_manager_ = std::make_unique<NullOverloadManager>(threadLocal(), false);
133
72
  absl::Status creation_status = absl::OkStatus();
134
72
  Configuration::InitialImpl initial_config(bootstrap_, creation_status);
135
72
  THROW_IF_NOT_OK_REF(creation_status);
136
72
  AdminFactoryContext factory_context(*this, std::make_shared<ListenerInfoImpl>());
137
72
  initial_config.initAdminAccessLog(bootstrap_, factory_context);
138
72
  admin_ = std::make_unique<Server::ValidationAdmin>(initial_config.admin().address());
139
72
  listener_manager_ = Config::Utility::getAndCheckFactoryByName<ListenerManagerFactory>(
140
72
                          Config::ServerExtensionValues::get().VALIDATION_LISTENER)
141
72
                          .createListenerManager(*this, nullptr, *this, false, quic_stat_names_);
142
72
  thread_local_.registerThread(*dispatcher_, true);
143

            
144
72
  runtime_ = component_factory.createRuntime(*this, initial_config);
145
72
  ENVOY_BUG(runtime_ != nullptr,
146
72
            "Component factory should not return nullptr from createRuntime()");
147
72
  drain_manager_ = component_factory.createDrainManager(*this);
148
72
  ENVOY_BUG(drain_manager_ != nullptr,
149
72
            "Component factory should not return nullptr from createDrainManager()");
150

            
151
72
  secret_manager_ = std::make_unique<Secret::SecretManagerImpl>(admin()->getConfigTracker());
152
72
  ssl_context_manager_ =
153
72
      std::make_unique<Extensions::TransportSockets::Tls::ContextManagerImpl>(server_contexts_);
154

            
155
72
  http_server_properties_cache_manager_ =
156
72
      std::make_unique<Http::HttpServerPropertiesCacheManagerImpl>(
157
72
          serverFactoryContext(), messageValidationContext().staticValidationVisitor(),
158
72
          thread_local_);
159

            
160
72
  xds_manager_ = std::make_unique<Config::XdsManagerImpl>(*dispatcher_, *api_, stats_store_,
161
72
                                                          *local_info_, validation_context_, *this);
162

            
163
72
  cluster_manager_factory_ = std::make_unique<Upstream::ValidationClusterManagerFactory>(
164
72
      server_contexts_, [this]() -> Network::DnsResolverSharedPtr { return this->dnsResolver(); },
165
72
      quic_stat_names_);
166
72
  THROW_IF_NOT_OK(config_.initialize(bootstrap_, *this, *cluster_manager_factory_));
167
67
  THROW_IF_NOT_OK(runtime().initialize(clusterManager()));
168
67
  clusterManager().setInitializedCb([this]() -> void { init_manager_.initialize(init_watcher_); });
169
67
}
170

            
171
74
void ValidationInstance::shutdown() {
172
  // This normally happens at the bottom of InstanceImpl::run(), but we don't have a run(). We can
173
  // do an abbreviated shutdown here since there's less to clean up -- for example, no workers to
174
  // exit.
175
74
  thread_local_.shutdownGlobalThreading();
176
74
  if (config_.clusterManager() != nullptr) {
177
48
    config_.clusterManager()->shutdown();
178
48
  }
179
74
  thread_local_.shutdownThread();
180
74
  dispatcher_->shutdown();
181
74
}
182

            
183
47
Network::DnsResolverSharedPtr ValidationInstance::dnsResolver() {
184
47
  envoy::config::core::v3::TypedExtensionConfig typed_dns_resolver_config;
185
47
  Network::DnsResolverFactory& dns_resolver_factory =
186
47
      Network::createDefaultDnsResolverFactory(typed_dns_resolver_config);
187
47
  return THROW_OR_RETURN_VALUE(
188
47
      dns_resolver_factory.createDnsResolver(dispatcher(), api(), typed_dns_resolver_config),
189
47
      Network::DnsResolverSharedPtr);
190
47
}
191

            
192
} // namespace Server
193
} // namespace Envoy