1
#include "source/exe/stripped_main_base.h"
2

            
3
#include <fstream>
4
#include <iostream>
5
#include <memory>
6
#include <new>
7

            
8
#include "envoy/config/listener/v3/listener.pb.h"
9

            
10
#include "source/common/common/compiler_requirements.h"
11
#include "source/common/common/logger.h"
12
#include "source/common/common/perf_annotation.h"
13
#include "source/common/network/utility.h"
14
#include "source/common/stats/thread_local_store.h"
15
#include "source/exe/platform_impl.h"
16
#include "source/server/drain_manager_impl.h"
17
#include "source/server/hot_restart_nop_impl.h"
18
#include "source/server/listener_hooks.h"
19
#include "source/server/options_impl_base.h"
20
#include "source/server/server.h"
21

            
22
#include "absl/debugging/symbolize.h"
23
#include "absl/strings/str_split.h"
24

            
25
#ifdef ENVOY_HOT_RESTART
26
#include "source/server/hot_restart_impl.h"
27
#endif
28

            
29
namespace Envoy {
30

            
31
43
Server::DrainManagerPtr ProdComponentFactory::createDrainManager(Server::Instance& server) {
32
  // The global drain manager only triggers on listener modification, which effectively is
33
  // hot restart at the global level. The per-listener drain managers decide whether to
34
  // to include /healthcheck/fail status.
35
43
  return std::make_unique<Server::DrainManagerImpl>(
36
43
      server, envoy::config::listener::v3::Listener::MODIFY_ONLY, server.dispatcher());
37
43
}
38

            
39
Runtime::LoaderPtr ProdComponentFactory::createRuntime(Server::Instance& server,
40
42
                                                       Server::Configuration::Initial& config) {
41
42
  return Server::InstanceUtil::createRuntime(server, config);
42
42
}
43

            
44
StrippedMainBase::StrippedMainBase(const Server::Options& options,
45
                                   Server::ComponentFactory& component_factory,
46
                                   std::unique_ptr<Server::Platform> platform_impl,
47
                                   Random::RandomGenerator& random_generator)
48
44
    : platform_impl_(std::move(platform_impl)), options_(options),
49
44
      component_factory_(component_factory), stats_allocator_(symbol_table_) {
50
  // Process the option to disable extensions as early as possible,
51
  // before we do any configuration loading.
52
44
  OptionsImplBase::disableExtensions(options_.disabledExtensions());
53

            
54
  // Enable core dumps as early as possible.
55
44
  if (options_.coreDumpEnabled()) {
56
3
    const auto ret = platform_impl_->enableCoreDump();
57
3
    if (ret) {
58
1
      ENVOY_LOG_MISC(info, "core dump enabled");
59
2
    } else {
60
2
      ENVOY_LOG_MISC(warn, "failed to enable core dump");
61
2
    }
62
3
  }
63

            
64
44
  switch (options_.mode()) {
65
2
  case Server::Mode::InitOnly:
66
42
  case Server::Mode::Serve:
67
42
    configureHotRestarter(random_generator);
68
42
    tls_ = std::make_unique<ThreadLocal::InstanceImpl>();
69
42
    stats_store_ = std::make_unique<Stats::ThreadLocalStoreImpl>(stats_allocator_);
70
42
    break;
71
2
  case Server::Mode::Validate:
72
2
    restarter_ = std::make_unique<Server::HotRestartNopImpl>();
73
2
    break;
74
44
  }
75
44
}
76

            
77
void StrippedMainBase::init(Event::TimeSystem& time_system, ListenerHooks& listener_hooks,
78
                            std::unique_ptr<Random::RandomGenerator>&& random_generator,
79
                            std::unique_ptr<ProcessContext> process_context,
80
43
                            CreateInstanceFunction create_instance) {
81
43
  switch (options_.mode()) {
82
2
  case Server::Mode::InitOnly:
83
41
  case Server::Mode::Serve: {
84
41
    configureComponentLogLevels();
85

            
86
41
    server_ = create_instance(*init_manager_, options_, time_system, listener_hooks, *restarter_,
87
41
                              *stats_store_, restarter_->accessLogLock(), component_factory_,
88
41
                              std::move(random_generator), *tls_, platform_impl_->threadFactory(),
89
41
                              platform_impl_->fileSystem(), std::move(process_context), nullptr);
90
41
    break;
91
2
  }
92
2
  case Server::Mode::Validate:
93
2
    process_context_ = std::move(process_context);
94
2
    break;
95
43
  }
96
43
}
97

            
98
41
void StrippedMainBase::configureComponentLogLevels() {
99
41
  for (auto& component_log_level : options_.componentLogLevels()) {
100
    Logger::Logger* logger_to_change = Logger::Registry::logger(component_log_level.first);
101
    ASSERT(logger_to_change);
102
    logger_to_change->setLevel(component_log_level.second);
103
  }
104
41
}
105

            
106
42
void StrippedMainBase::configureHotRestarter(Random::RandomGenerator& random_generator) {
107
42
#ifdef ENVOY_HOT_RESTART
108
42
  if (!options_.hotRestartDisabled()) {
109
11
    uint32_t base_id = options_.baseId();
110

            
111
11
    if (options_.useDynamicBaseId()) {
112
11
      ASSERT(options_.restartEpoch() == 0, "cannot use dynamic base id during hot restart");
113

            
114
11
      std::unique_ptr<Server::HotRestart> restarter;
115

            
116
      // Try 100 times to get an unused base ID and then give up under the assumption
117
      // that some other problem has occurred to prevent binding the domain socket.
118
121
      for (int i = 0; i < 100 && restarter == nullptr; i++) {
119
        // HotRestartImpl is going to multiply this value by 10, so leave head room.
120
110
        base_id = static_cast<uint32_t>(random_generator.random()) & 0x0FFFFFFF;
121

            
122
110
        TRY_ASSERT_MAIN_THREAD {
123
110
          restarter = std::make_unique<Server::HotRestartImpl>(
124
110
              base_id, 0, options_.socketPath(), options_.socketMode(),
125
110
              options_.skipHotRestartOnNoParent(), options_.skipHotRestartParentStats());
126
110
        }
127
110
        END_TRY
128
110
        CATCH(Server::HotRestartDomainSocketInUseException & ex, {
129
          // No luck, try again.
130
110
          ENVOY_LOG_MISC(debug, "dynamic base id: {}", ex.what());
131
110
        });
132
110
      }
133

            
134
11
      if (restarter == nullptr) {
135
1
        throw EnvoyException("unable to select a dynamic base id");
136
1
      }
137

            
138
10
      restarter_.swap(restarter);
139
10
    } else {
140
      restarter_ = std::make_unique<Server::HotRestartImpl>(
141
          base_id, options_.restartEpoch(), options_.socketPath(), options_.socketMode(),
142
          options_.skipHotRestartOnNoParent(), options_.skipHotRestartParentStats());
143
    }
144

            
145
    // Write the base-id to the requested path whether we selected it
146
    // dynamically or not.
147
10
    if (!options_.baseIdPath().empty()) {
148
2
      std::ofstream base_id_out_file(options_.baseIdPath());
149
2
      if (!base_id_out_file) {
150
        ENVOY_LOG_MISC(critical, "cannot open base id output file {} for writing.",
151
                       options_.baseIdPath());
152
2
      } else {
153
2
        base_id_out_file << base_id;
154
2
      }
155
2
    }
156
10
  }
157
#else
158
  UNREFERENCED_PARAMETER(random_generator);
159
#endif
160

            
161
41
  if (restarter_ == nullptr) {
162
31
    restarter_ = std::make_unique<Server::HotRestartNopImpl>();
163
31
  }
164
41
}
165

            
166
} // namespace Envoy