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

            
3
#include <chrono>
4
#include <cstdint>
5
#include <iostream>
6
#include <string>
7

            
8
#include "envoy/admin/v3/server_info.pb.h"
9

            
10
#include "source/common/common/fmt.h"
11
#include "source/common/common/logger.h"
12
#include "source/common/common/macros.h"
13
#include "source/common/protobuf/utility.h"
14
#include "source/common/stats/tag_utility.h"
15
#include "source/common/version/version.h"
16
#include "source/server/options_impl_platform.h"
17

            
18
#include "absl/strings/str_replace.h"
19
#include "absl/strings/str_split.h"
20
#include "absl/strings/string_view.h"
21
#include "spdlog/spdlog.h"
22
#include "tclap/CmdLine.h"
23

            
24
namespace Envoy {
25
namespace {
26
1709
std::vector<std::string> toArgsVector(int argc, const char* const* argv) {
27
1709
  std::vector<std::string> args;
28
1709
  args.reserve(argc);
29

            
30
5257
  for (int i = 0; i < argc; ++i) {
31
3548
    args.emplace_back(argv[i]);
32
3548
  }
33
1709
  return args;
34
1709
}
35

            
36
} // namespace
37

            
38
OptionsImpl::OptionsImpl(int argc, const char* const* argv,
39
                         const HotRestartVersionCb& hot_restart_version_cb,
40
                         spdlog::level::level_enum default_log_level)
41
1709
    : OptionsImpl(toArgsVector(argc, argv), hot_restart_version_cb, default_log_level) {}
42

            
43
OptionsImpl::OptionsImpl(std::vector<std::string> args,
44
                         const HotRestartVersionCb& hot_restart_version_cb,
45
1759
                         spdlog::level::level_enum default_log_level) {
46
1759
  std::string log_levels_string = fmt::format("Log levels: {}", allowedLogLevels());
47
1759
  log_levels_string +=
48
1759
      fmt::format("\nDefault is [{}]", spdlog::level::level_string_views[default_log_level]);
49

            
50
1759
  const std::string component_log_level_string =
51
1759
      "Comma-separated list of component log levels. For example upstream:debug,config:trace";
52
1759
  const std::string log_format_string =
53
1759
      fmt::format("Log message format in spdlog syntax "
54
1759
                  "(see https://github.com/gabime/spdlog/wiki/3.-Custom-formatting)"
55
1759
                  "\nDefault is \"{}\"",
56
1759
                  Logger::Logger::DEFAULT_LOG_FORMAT);
57

            
58
  // NOLINTNEXTLINE(clang-analyzer-optin.cplusplus.VirtualCall)
59
1759
  TCLAP::CmdLine cmd("envoy", ' ', VersionInfo::version());
60
1759
  TCLAP::ValueArg<uint32_t> base_id(
61
1759
      "", "base-id", "Base ID so that multiple envoys can run on the same host if needed", false, 0,
62
1759
      "uint32_t", cmd);
63
1759
  TCLAP::SwitchArg use_dynamic_base_id(
64
1759
      "", "use-dynamic-base-id",
65
1759
      "The server chooses a base ID dynamically. Supersedes a static base ID. May not be used "
66
1759
      "when the restart epoch is non-zero.",
67
1759
      cmd, false);
68
1759
  TCLAP::SwitchArg skip_hot_restart_on_no_parent(
69
1759
      "", "skip-hot-restart-on-no-parent",
70
1759
      "When hot restarting with epoch>0, the default behavior is for the child to crash if the"
71
1759
      " connection to the parent cannot be established. Set this to true to instead continue with"
72
1759
      " a regular startup, while retaining the new epoch value.",
73
1759
      cmd, false);
74
1759
  TCLAP::SwitchArg skip_hot_restart_parent_stats(
75
1759
      "", "skip-hot-restart-parent-stats",
76
1759
      "When hot restarting, by default the child instance copies stats from the parent"
77
1759
      " instance periodically during the draining period. This can potentially be an"
78
1759
      " expensive operation; set this to true to reset all stats in child process.",
79
1759
      cmd, false);
80
1759
  TCLAP::ValueArg<std::string> base_id_path(
81
1759
      "", "base-id-path", "Path to which the base ID is written", false, "", "string", cmd);
82
1759
  TCLAP::ValueArg<uint32_t> concurrency("", "concurrency", "# of worker threads to run", false,
83
1759
                                        std::thread::hardware_concurrency(), "uint32_t", cmd);
84
1759
  TCLAP::ValueArg<std::string> config_path("c", "config-path", "Path to configuration file", false,
85
1759
                                           "", "string", cmd);
86
1759
  TCLAP::ValueArg<std::string> config_yaml(
87
1759
      "", "config-yaml", "Inline YAML configuration, merges with the contents of --config-path",
88
1759
      false, "", "string", cmd);
89

            
90
1759
  TCLAP::SwitchArg allow_unknown_fields("", "allow-unknown-fields",
91
1759
                                        "Allow unknown fields in static configuration (DEPRECATED)",
92
1759
                                        cmd, false);
93
1759
  TCLAP::SwitchArg allow_unknown_static_fields("", "allow-unknown-static-fields",
94
1759
                                               "Allow unknown fields in static configuration", cmd,
95
1759
                                               false);
96
1759
  TCLAP::SwitchArg reject_unknown_dynamic_fields("", "reject-unknown-dynamic-fields",
97
1759
                                                 "Reject unknown fields in dynamic configuration",
98
1759
                                                 cmd, false);
99
1759
  TCLAP::SwitchArg ignore_unknown_dynamic_fields("", "ignore-unknown-dynamic-fields",
100
1759
                                                 "Ignore unknown fields in dynamic configuration",
101
1759
                                                 cmd, false);
102
1759
  TCLAP::SwitchArg skip_deprecated_logs(
103
1759
      "", "skip-deprecated-logs",
104
1759
      "Skips the logging of deprecated field warnings during Protobuf message validation", cmd,
105
1759
      false);
106

            
107
1759
  TCLAP::ValueArg<std::string> admin_address_path("", "admin-address-path", "Admin address path",
108
1759
                                                  false, "", "string", cmd);
109
1759
  TCLAP::ValueArg<std::string> local_address_ip_version("", "local-address-ip-version",
110
1759
                                                        "The local "
111
1759
                                                        "IP address version (v4 or v6).",
112
1759
                                                        false, "v4", "string", cmd);
113
1759
  TCLAP::ValueArg<std::string> log_level(
114
1759
      "l", "log-level", log_levels_string, false,
115
1759
      spdlog::level::level_string_views[default_log_level].data(), "string", cmd);
116
1759
  TCLAP::ValueArg<std::string> component_log_level(
117
1759
      "", "component-log-level", component_log_level_string, false, "", "string", cmd);
118
1759
  TCLAP::ValueArg<std::string> log_format("", "log-format", log_format_string, false,
119
1759
                                          Logger::Logger::DEFAULT_LOG_FORMAT, "string", cmd);
120
1759
  TCLAP::SwitchArg log_format_escaped("", "log-format-escaped",
121
1759
                                      "Escape c-style escape sequences in the application logs",
122
1759
                                      cmd, false);
123
1759
  TCLAP::SwitchArg enable_fine_grain_logging(
124
1759
      "", "enable-fine-grain-logging",
125
1759
      "Logger mode: enable file level log control (Fine-Grain Logger) or not", cmd, false);
126
1759
  TCLAP::ValueArg<std::string> log_path("", "log-path", "Path to logfile", false, "", "string",
127
1759
                                        cmd);
128
1759
  TCLAP::ValueArg<uint32_t> restart_epoch("", "restart-epoch", "Hot restart epoch #", false, 0,
129
1759
                                          "uint32_t", cmd);
130
1759
  TCLAP::SwitchArg hot_restart_version_option("", "hot-restart-version",
131
1759
                                              "Hot restart compatibility version", cmd);
132
1759
  TCLAP::ValueArg<std::string> service_cluster("", "service-cluster", "Cluster name", false, "",
133
1759
                                               "string", cmd);
134
1759
  TCLAP::ValueArg<std::string> service_node("", "service-node", "Node name", false, "", "string",
135
1759
                                            cmd);
136
1759
  TCLAP::ValueArg<std::string> service_zone("", "service-zone", "Zone name", false, "", "string",
137
1759
                                            cmd);
138
1759
  TCLAP::ValueArg<uint32_t> file_flush_interval_msec("", "file-flush-interval-msec",
139
1759
                                                     "Interval for log flushing in msec", false,
140
1759
                                                     10000, "uint32_t", cmd);
141
1759
  TCLAP::ValueArg<uint32_t> file_flush_min_size_kb("", "file-flush-min-size-kb",
142
1759
                                                   "Minimum size in KB for log flushing", false, 64,
143
1759
                                                   "uint32_t", cmd);
144
1759
  TCLAP::ValueArg<uint32_t> drain_time_s("", "drain-time-s",
145
1759
                                         "Hot restart and LDS removal drain time in seconds", false,
146
1759
                                         600, "uint32_t", cmd);
147
1759
  TCLAP::ValueArg<std::string> drain_strategy(
148
1759
      "", "drain-strategy",
149
1759
      "Hot restart drain sequence behaviour, one of 'gradual' (default) or 'immediate'.", false,
150
1759
      "gradual", "string", cmd);
151
1759
  TCLAP::ValueArg<uint32_t> parent_shutdown_time_s("", "parent-shutdown-time-s",
152
1759
                                                   "Hot restart parent shutdown time in seconds",
153
1759
                                                   false, 900, "uint32_t", cmd);
154
1759
  TCLAP::ValueArg<std::string> mode("", "mode",
155
1759
                                    "One of 'serve' (default; validate configs and then serve "
156
1759
                                    "traffic normally) or 'validate' (validate configs and exit).",
157
1759
                                    false, "serve", "string", cmd);
158
1759
  TCLAP::SwitchArg disable_hot_restart("", "disable-hot-restart",
159
1759
                                       "Disable hot restart functionality", cmd, false);
160
1759
  TCLAP::SwitchArg enable_mutex_tracing(
161
1759
      "", "enable-mutex-tracing", "Enable mutex contention tracing functionality", cmd, false);
162
1759
  TCLAP::SwitchArg cpuset_threads(
163
1759
      "", "cpuset-threads", "Get the default # of worker threads from cpuset size", cmd, false);
164

            
165
1759
  TCLAP::ValueArg<std::string> disable_extensions("", "disable-extensions",
166
1759
                                                  "Comma-separated list of extensions to disable",
167
1759
                                                  false, "", "string", cmd);
168

            
169
1759
  TCLAP::ValueArg<std::string> socket_path("", "socket-path", "Path to hot restart socket file",
170
1759
                                           false, "@envoy_domain_socket", "string", cmd);
171

            
172
1759
  TCLAP::ValueArg<std::string> socket_mode("", "socket-mode", "Socket file permission", false,
173
1759
                                           "600", "string", cmd);
174
1759
  TCLAP::SwitchArg enable_core_dump("", "enable-core-dump", "Enable core dumps", cmd, false);
175

            
176
1759
  TCLAP::MultiArg<std::string> stats_tag(
177
1759
      "", "stats-tag",
178
1759
      "This flag provides a universal tag for all stats generated by Envoy. The format is "
179
1759
      "``tag:value``. Only alphanumeric values are allowed for tag names. For tag values all "
180
1759
      "characters are permitted except for '.' (dot). This flag can be repeated multiple times to "
181
1759
      "set multiple universal tags. Multiple values for the same tag name are not allowed.",
182
1759
      false, "string", cmd);
183

            
184
1759
  cmd.setExceptionHandling(false);
185

            
186
1759
  std::function failure_function = [&](TCLAP::ArgException& e) {
187
2
    TRY_ASSERT_MAIN_THREAD { cmd.getOutput()->failure(cmd, e); }
188
2
    END_TRY
189
2
    CATCH(const TCLAP::ExitException&, {
190
      // failure() has already written an informative message to stderr, so all that's left to do
191
      // is throw our own exception with the original message.
192
2
      throw MalformedArgvException(e.what());
193
2
    });
194
  };
195

            
196
1759
  TRY_ASSERT_MAIN_THREAD {
197
1759
    cmd.parse(args);
198
1759
    count_ = cmd.getArgList().size();
199
1759
  }
200
1759
  END_TRY
201
1759
  MULTI_CATCH(
202
1759
      TCLAP::ArgException & e, { failure_function(e); },
203
1759
      { throw NoServingException("NoServingException"); });
204

            
205
1757
  hot_restart_disabled_ = disable_hot_restart.getValue();
206
1757
  mutex_tracing_enabled_ = enable_mutex_tracing.getValue();
207
1757
  core_dump_enabled_ = enable_core_dump.getValue();
208

            
209
1757
  cpuset_threads_ = cpuset_threads.getValue();
210

            
211
1757
  if (log_level.isSet()) {
212
5
    auto status_or_error = parseAndValidateLogLevel(log_level.getValue());
213
5
    if (!status_or_error.status().ok()) {
214
1
      logError(std::string(status_or_error.status().message()));
215
1
    }
216
5
    log_level_ = status_or_error.value();
217
1752
  } else {
218
1752
    log_level_ = default_log_level;
219
1752
  }
220

            
221
1757
  log_format_ = log_format.getValue();
222
1757
  log_format_set_ = log_format.isSet();
223
1757
  log_format_escaped_ = log_format_escaped.getValue();
224

            
225
1757
  enable_fine_grain_logging_ = enable_fine_grain_logging.getValue();
226
1757
  if (enable_fine_grain_logging_ && !component_log_level.getValue().empty()) {
227
1
    throw MalformedArgvException(
228
1
        "error: --component-log-level will not work with --enable-fine-grain-logging");
229
1
  }
230

            
231
1756
  parseComponentLogLevels(component_log_level.getValue());
232

            
233
1756
  if (mode.getValue() == "serve") {
234
1734
    mode_ = Server::Mode::Serve;
235
1735
  } else if (mode.getValue() == "validate") {
236
5
    mode_ = Server::Mode::Validate;
237
17
  } else if (mode.getValue() == "init_only") {
238
11
    mode_ = Server::Mode::InitOnly;
239
15
  } else {
240
6
    const std::string message = fmt::format("error: unknown mode '{}'", mode.getValue());
241
6
    throw MalformedArgvException(message);
242
6
  }
243

            
244
1750
  if (local_address_ip_version.getValue() == "v4") {
245
1746
    local_address_ip_version_ = Network::Address::IpVersion::v4;
246
1746
  } else if (local_address_ip_version.getValue() == "v6") {
247
2
    local_address_ip_version_ = Network::Address::IpVersion::v6;
248
3
  } else {
249
2
    const std::string message =
250
2
        fmt::format("error: unknown IP address version '{}'", local_address_ip_version.getValue());
251
2
    throw MalformedArgvException(message);
252
2
  }
253
1748
  base_id_ = base_id.getValue();
254
1748
  use_dynamic_base_id_ = use_dynamic_base_id.getValue();
255
1748
  skip_hot_restart_on_no_parent_ = skip_hot_restart_on_no_parent.getValue();
256
1748
  skip_hot_restart_parent_stats_ = skip_hot_restart_parent_stats.getValue();
257
1748
  base_id_path_ = base_id_path.getValue();
258
1748
  restart_epoch_ = restart_epoch.getValue();
259

            
260
1748
  if (use_dynamic_base_id_ && restart_epoch_ > 0) {
261
1
    const std::string message = fmt::format(
262
1
        "error: cannot use --restart-epoch={} with --use-dynamic-base-id", restart_epoch_);
263
1
    throw MalformedArgvException(message);
264
1
  }
265

            
266
1747
  if (!concurrency.isSet() && cpuset_threads_) {
267
    // The 'concurrency' command line option wasn't set but the 'cpuset-threads'
268
    // option was set. Use the number of CPUs assigned to the process cpuset, if
269
    // that can be known.
270
1
    concurrency_ = OptionsImplPlatform::getCpuCount();
271
1746
  } else {
272
1746
    if (concurrency.isSet() && cpuset_threads_ && cpuset_threads.isSet()) {
273
2
      ENVOY_LOG(warn, "Both --concurrency and --cpuset-threads options are set; not applying "
274
2
                      "--cpuset-threads.");
275
2
    }
276
1746
    concurrency_ = std::max(1U, concurrency.getValue());
277
1746
  }
278

            
279
1747
  config_path_ = config_path.getValue();
280
1747
  config_yaml_ = config_yaml.getValue();
281
1747
  if (allow_unknown_fields.getValue()) {
282
3
    if (!skip_deprecated_logs.getValue()) {
283
2
      ENVOY_LOG(warn,
284
2
                "--allow-unknown-fields is deprecated, use --allow-unknown-static-fields instead.");
285
2
    }
286
3
  }
287
1747
  allow_unknown_static_fields_ =
288
1747
      allow_unknown_static_fields.getValue() || allow_unknown_fields.getValue();
289
1747
  reject_unknown_dynamic_fields_ = reject_unknown_dynamic_fields.getValue();
290
1747
  ignore_unknown_dynamic_fields_ = ignore_unknown_dynamic_fields.getValue();
291
1747
  skip_deprecated_logs_ = skip_deprecated_logs.getValue();
292
1747
  admin_address_path_ = admin_address_path.getValue();
293
1747
  log_path_ = log_path.getValue();
294
1747
  service_cluster_ = service_cluster.getValue();
295
1747
  service_node_ = service_node.getValue();
296
1747
  service_zone_ = service_zone.getValue();
297
1747
  file_flush_interval_msec_ = std::chrono::milliseconds(file_flush_interval_msec.getValue());
298
1747
  file_flush_min_size_kb_ = file_flush_min_size_kb.getValue();
299
1747
  drain_time_ = std::chrono::seconds(drain_time_s.getValue());
300
1747
  parent_shutdown_time_ = std::chrono::seconds(parent_shutdown_time_s.getValue());
301
1747
  socket_path_ = socket_path.getValue();
302

            
303
1747
  if (socket_path_.at(0) == '@') {
304
1745
    socket_mode_ = 0;
305
1745
  } else {
306
2
    uint64_t socket_mode_helper;
307
2
    if (!StringUtil::atoull(socket_mode.getValue().c_str(), socket_mode_helper, 8)) {
308
1
      throw MalformedArgvException(
309
1
          fmt::format("error: invalid socket-mode '{}'", socket_mode.getValue()));
310
1
    }
311
1
    socket_mode_ = socket_mode_helper;
312
1
  }
313

            
314
1746
  if (drain_strategy.getValue() == "immediate") {
315
    drain_strategy_ = Server::DrainStrategy::Immediate;
316
1746
  } else if (drain_strategy.getValue() == "gradual") {
317
1746
    drain_strategy_ = Server::DrainStrategy::Gradual;
318
1746
  } else {
319
    throw MalformedArgvException(
320
        fmt::format("error: unknown drain-strategy '{}'", mode.getValue()));
321
  }
322

            
323
1746
  if (hot_restart_version_option.getValue()) {
324
1
    std::cerr << hot_restart_version_cb(!hot_restart_disabled_);
325
1
    throw NoServingException("NoServingException");
326
1
  }
327

            
328
1745
  if (!disable_extensions.getValue().empty()) {
329
    disabled_extensions_ = absl::StrSplit(disable_extensions.getValue(), ',');
330
  }
331

            
332
1745
  if (!stats_tag.getValue().empty()) {
333
9
    for (const auto& cli_tag_pair : stats_tag.getValue()) {
334

            
335
9
      std::vector<absl::string_view> cli_tag_pair_tokens =
336
9
          absl::StrSplit(cli_tag_pair, absl::MaxSplits(':', 1));
337
9
      if (cli_tag_pair_tokens.size() != 2) {
338
1
        throw MalformedArgvException(
339
1
            fmt::format("error: misformatted stats-tag '{}'", cli_tag_pair));
340
1
      }
341

            
342
8
      auto name = cli_tag_pair_tokens[0];
343
8
      if (!Stats::TagUtility::isTagNameValid(name)) {
344
1
        throw MalformedArgvException(
345
1
            fmt::format("error: misformatted stats-tag '{}' contains invalid char in '{}'",
346
1
                        cli_tag_pair, name));
347
1
      }
348

            
349
7
      auto value = cli_tag_pair_tokens[1];
350
7
      if (!Stats::TagUtility::isTagValueValid(value)) {
351
2
        throw MalformedArgvException(
352
2
            fmt::format("error: misformatted stats-tag '{}' contains invalid char in '{}'",
353
2
                        cli_tag_pair, value));
354
2
      }
355

            
356
5
      stats_tags_.emplace_back(Stats::Tag{std::string(name), std::string(value)});
357
5
    }
358
8
  }
359
1745
}
360

            
361
1760
std::string OptionsImpl::allowedLogLevels() {
362
1760
  std::string allowed_log_levels;
363
12320
  for (auto level_string_view : spdlog::level::level_string_views) {
364
12320
    if (level_string_view == spdlog::level::to_string_view(spdlog::level::warn)) {
365
1760
      allowed_log_levels += fmt::format("[{}|warn]", level_string_view);
366
10560
    } else {
367
10560
      allowed_log_levels += fmt::format("[{}]", level_string_view);
368
10560
    }
369
12320
  }
370
1760
  return allowed_log_levels;
371
1760
}
372

            
373
1762
void OptionsImpl::parseComponentLogLevels(const std::string& component_log_levels) {
374
1762
  if (component_log_levels.empty()) {
375
1752
    return;
376
1752
  }
377
10
  component_log_level_str_ = component_log_levels;
378
10
  std::vector<std::string> log_levels = absl::StrSplit(component_log_levels, ',');
379
12
  for (auto& level : log_levels) {
380
12
    std::vector<std::string> log_name_level = absl::StrSplit(level, ':');
381
12
    if (log_name_level.size() != 2) {
382
3
      logError(fmt::format("error: component log level not correctly specified '{}'", level));
383
3
    }
384
12
    std::string log_name = log_name_level[0];
385
12
    auto status_or_error = parseAndValidateLogLevel(log_name_level[1]);
386
12
    if (!status_or_error.status().ok()) {
387
3
      logError(std::string(status_or_error.status().message()));
388
3
    }
389
12
    spdlog::level::level_enum log_level = status_or_error.value();
390
12
    Logger::Logger* logger_to_change = Logger::Registry::logger(log_name);
391
12
    if (!logger_to_change) {
392
2
      logError(fmt::format("error: invalid component specified '{}'", log_name));
393
2
    }
394
12
    component_log_levels_.push_back(std::make_pair(log_name, log_level));
395
12
  }
396
10
}
397

            
398
9
void OptionsImpl::logError(const std::string& error) { throw MalformedArgvException(error); }
399

            
400
3
Server::CommandLineOptionsPtr OptionsImpl::toCommandLineOptions() const {
401
3
  Server::CommandLineOptionsPtr command_line_options =
402
3
      std::make_unique<envoy::admin::v3::CommandLineOptions>();
403
3
  command_line_options->set_base_id(baseId());
404
3
  command_line_options->set_use_dynamic_base_id(useDynamicBaseId());
405
3
  command_line_options->set_skip_hot_restart_on_no_parent(skipHotRestartOnNoParent());
406
3
  command_line_options->set_skip_hot_restart_parent_stats(skipHotRestartParentStats());
407
3
  command_line_options->set_base_id_path(baseIdPath());
408
3
  command_line_options->set_concurrency(concurrency());
409
3
  command_line_options->set_config_path(configPath());
410
3
  command_line_options->set_config_yaml(configYaml());
411
3
  command_line_options->set_allow_unknown_static_fields(allow_unknown_static_fields_);
412
3
  command_line_options->set_reject_unknown_dynamic_fields(reject_unknown_dynamic_fields_);
413
3
  command_line_options->set_ignore_unknown_dynamic_fields(ignore_unknown_dynamic_fields_);
414
3
  command_line_options->set_skip_deprecated_logs(skip_deprecated_logs_);
415
3
  command_line_options->set_admin_address_path(adminAddressPath());
416
3
  command_line_options->set_component_log_level(component_log_level_str_);
417
3
  command_line_options->set_log_level(spdlog::level::to_string_view(logLevel()).data(),
418
3
                                      spdlog::level::to_string_view(logLevel()).size());
419
3
  command_line_options->set_log_format(logFormat());
420
3
  command_line_options->set_log_format_escaped(logFormatEscaped());
421
3
  command_line_options->set_enable_fine_grain_logging(enableFineGrainLogging());
422
3
  command_line_options->set_log_path(logPath());
423
3
  command_line_options->set_service_cluster(serviceClusterName());
424
3
  command_line_options->set_service_node(serviceNodeName());
425
3
  command_line_options->set_service_zone(serviceZone());
426
3
  if (mode() == Server::Mode::Serve) {
427
2
    command_line_options->set_mode(envoy::admin::v3::CommandLineOptions::Serve);
428
2
  } else if (mode() == Server::Mode::Validate) {
429
1
    command_line_options->set_mode(envoy::admin::v3::CommandLineOptions::Validate);
430
1
  } else {
431
    command_line_options->set_mode(envoy::admin::v3::CommandLineOptions::InitOnly);
432
  }
433
3
  if (localAddressIpVersion() == Network::Address::IpVersion::v4) {
434
2
    command_line_options->set_local_address_ip_version(envoy::admin::v3::CommandLineOptions::v4);
435
2
  } else {
436
1
    command_line_options->set_local_address_ip_version(envoy::admin::v3::CommandLineOptions::v6);
437
1
  }
438
3
  command_line_options->mutable_file_flush_interval()->MergeFrom(
439
3
      Protobuf::util::TimeUtil::MillisecondsToDuration(fileFlushIntervalMsec().count()));
440

            
441
3
  command_line_options->mutable_drain_time()->MergeFrom(
442
3
      Protobuf::util::TimeUtil::SecondsToDuration(drainTime().count()));
443
3
  command_line_options->set_drain_strategy(drainStrategy() == Server::DrainStrategy::Immediate
444
3
                                               ? envoy::admin::v3::CommandLineOptions::Immediate
445
3
                                               : envoy::admin::v3::CommandLineOptions::Gradual);
446
3
  command_line_options->mutable_parent_shutdown_time()->MergeFrom(
447
3
      Protobuf::util::TimeUtil::SecondsToDuration(parentShutdownTime().count()));
448

            
449
3
  command_line_options->set_disable_hot_restart(hotRestartDisabled());
450
3
  command_line_options->set_enable_mutex_tracing(mutexTracingEnabled());
451
3
  command_line_options->set_cpuset_threads(cpusetThreadsEnabled());
452
3
  command_line_options->set_restart_epoch(restartEpoch());
453
3
  for (const auto& e : disabledExtensions()) {
454
    command_line_options->add_disabled_extensions(e);
455
  }
456
3
  command_line_options->set_socket_path(socketPath());
457
3
  command_line_options->set_socket_mode(socketMode());
458
3
  for (const auto& tag : statsTags()) {
459
1
    command_line_options->add_stats_tag(fmt::format("{}:{}", tag.name_, tag.value_));
460
1
  }
461
3
  return command_line_options;
462
3
}
463

            
464
OptionsImpl::OptionsImpl(const std::string& service_cluster, const std::string& service_node,
465
1
                         const std::string& service_zone, spdlog::level::level_enum log_level) {
466
1
  setLogLevel(log_level);
467
1
  setServiceClusterName(service_cluster);
468
1
  setServiceNodeName(service_node);
469
1
  setServiceZone(service_zone);
470
1
}
471

            
472
} // namespace Envoy