/*
* Copyright (C) 2013 10gen Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kControl
#include "mongo/db/server_options_helpers.h"
#ifdef _WIN32
#include
#else
#define SYSLOG_NAMES
#include
#endif
#include
#include
#include
#include
#include "mongo/base/status.h"
#include "mongo/bson/util/builder.h"
#include "mongo/config.h"
#include "mongo/db/server_options.h"
#include "mongo/db/server_parameters.h"
#include "mongo/logger/log_component.h"
#include "mongo/logger/message_event_utf8_encoder.h"
#include "mongo/transport/message_compressor_registry.h"
#include "mongo/util/cmdline_utils/censor_cmdline.h"
#include "mongo/util/fail_point_service.h"
#include "mongo/util/log.h"
#include "mongo/util/map_util.h"
#include "mongo/util/mongoutils/str.h"
#include "mongo/util/net/listen.h" // For DEFAULT_MAX_CONN
#include "mongo/util/net/ssl_options.h"
#include "mongo/util/options_parser/startup_options.h"
using std::endl;
using std::string;
namespace mongo {
/*
* SERVER-11160 syslog.h does not define facilitynames under solaris.
* syslog.h exports preprocessor macro INTERNAL_NOPRI if
* facilitynames is provided. This will be used to determine
* if facilitynames should be defined here.
* These could also go into a syslog.h compatibility header.
* We are using INTERNAL_NOPRI as the indicator macro for facilitynames
* because it's defined alongside facilitynames in the syslog.h headers
* that support SYSLOG_NAMES.
*/
namespace {
#if defined(SYSLOG_NAMES)
#if !defined(INTERNAL_NOPRI)
typedef struct _code {
const char* c_name;
int c_val;
} CODE;
CODE facilitynames[] = {{"auth", LOG_AUTH}, {"cron", LOG_CRON}, {"daemon", LOG_DAEMON},
{"kern", LOG_KERN}, {"lpr", LOG_LPR}, {"mail", LOG_MAIL},
{"news", LOG_NEWS}, {"security", LOG_AUTH}, /* DEPRECATED */
{"syslog", LOG_SYSLOG}, {"user", LOG_USER}, {"uucp", LOG_UUCP},
{"local0", LOG_LOCAL0}, {"local1", LOG_LOCAL1}, {"local2", LOG_LOCAL2},
{"local3", LOG_LOCAL3}, {"local4", LOG_LOCAL4}, {"local5", LOG_LOCAL5},
{"local6", LOG_LOCAL6}, {"local7", LOG_LOCAL7}, {NULL, -1}};
#endif // !defined(INTERNAL_NOPRI)
#endif // defined(SYSLOG_NAMES)
} // namespace
Status addGeneralServerOptions(moe::OptionSection* options) {
StringBuilder portInfoBuilder;
StringBuilder maxConnInfoBuilder;
std::stringstream unixSockPermsBuilder;
portInfoBuilder << "specify port number - " << ServerGlobalParams::DefaultDBPort
<< " by default";
maxConnInfoBuilder << "max number of simultaneous connections - " << DEFAULT_MAX_CONN
<< " by default";
unixSockPermsBuilder << "permissions to set on UNIX domain socket file - "
<< "0" << std::oct << DEFAULT_UNIX_PERMS << " by default";
options->addOptionChaining("help", "help,h", moe::Switch, "show this usage information")
.setSources(moe::SourceAllLegacy);
options->addOptionChaining("version", "version", moe::Switch, "show version information")
.setSources(moe::SourceAllLegacy);
options
->addOptionChaining(
"config", "config,f", moe::String, "configuration file specifying additional options")
.setSources(moe::SourceAllLegacy);
// The verbosity level can be set at startup in the following ways. Note that if multiple
// methods for setting the verbosity are specified simultaneously, the verbosity will be set
// based on the whichever option specifies the highest level
//
// Command Line Option | Resulting Verbosity
// _________________________________________
// (none) | 0
// --verbose "" | Error after Boost 1.59
// --verbose | 1
// --verbose v | 1
// --verbose vv | 2 (etc.)
// -v | 1
// -vv | 2 (etc.)
//
// INI Config Option | Resulting Verbosity
// _________________________________________
// verbose= | 0
// verbose=v | 1
// verbose=vv | 2 (etc.)
// v=true | 1
// vv=true | 2 (etc.)
//
// YAML Config Option | Resulting Verbosity
// _________________________________________
// systemLog: |
// verbosity: 5 | 5
// systemLog: |
// component: |
// verbosity: 5 | 5
// systemLog: |
// component: |
// Sharding: |
// verbosity: 5 | 5 (for Sharding only, 0 for default)
options
->addOptionChaining(
"verbose",
"verbose,v",
moe::String,
"be more verbose (include multiple times for more verbosity e.g. -vvvvv)")
.setImplicit(moe::Value(std::string("v")))
.setSources(moe::SourceAllLegacy);
options->addOptionChaining("systemLog.verbosity", "", moe::Int, "set verbose level")
.setSources(moe::SourceYAMLConfig);
// log component hierarchy verbosity levels
for (int i = 0; i < int(logger::LogComponent::kNumLogComponents); ++i) {
logger::LogComponent component = static_cast(i);
if (component == logger::LogComponent::kDefault) {
continue;
}
options
->addOptionChaining("systemLog.component." + component.getDottedName() + ".verbosity",
"",
moe::Int,
"set component verbose level for " + component.getDottedName())
.setSources(moe::SourceYAMLConfig);
}
options->addOptionChaining("systemLog.quiet", "quiet", moe::Switch, "quieter output");
options->addOptionChaining("net.port", "port", moe::Int, portInfoBuilder.str().c_str());
options
->addOptionChaining(
"net.bindIp",
"bind_ip",
moe::String,
"comma separated list of ip addresses to listen on - localhost by default")
.incompatibleWith("bind_ip_all");
options
->addOptionChaining("net.bindIpAll", "bind_ip_all", moe::Switch, "bind to all ip addresses")
.incompatibleWith("bind_ip");
options->addOptionChaining(
"net.ipv6", "ipv6", moe::Switch, "enable IPv6 support (disabled by default)");
options
->addOptionChaining(
"net.listenBacklog", "listenBacklog", moe::Int, "set socket listen backlog size")
.setDefault(moe::Value(SOMAXCONN));
options->addOptionChaining(
"net.maxIncomingConnections", "maxConns", moe::Int, maxConnInfoBuilder.str().c_str());
options
->addOptionChaining("net.transportLayer",
"transportLayer",
moe::String,
"sets the ingress transport layer implementation")
.hidden()
.setDefault(moe::Value("asio"));
options
->addOptionChaining("net.serviceExecutor",
"serviceExecutor",
moe::String,
"sets the service executor implementation")
.hidden()
.setDefault(moe::Value("synchronous"));
options
->addOptionChaining(
"logpath",
"logpath",
moe::String,
"log file to send write to instead of stdout - has to be a file, not directory")
.setSources(moe::SourceAllLegacy)
.incompatibleWith("syslog");
options
->addOptionChaining(
"systemLog.path",
"",
moe::String,
"log file to send writes to if logging to a file - has to be a file, not directory")
.setSources(moe::SourceYAMLConfig)
.hidden();
options
->addOptionChaining("systemLog.destination",
"",
moe::String,
"Destination of system log output. (syslog/file)")
.setSources(moe::SourceYAMLConfig)
.hidden()
.format("(:?syslog)|(:?file)", "(syslog/file)");
#ifndef _WIN32
options
->addOptionChaining("syslog",
"syslog",
moe::Switch,
"log to system's syslog facility instead of file or stdout")
.incompatibleWith("logpath")
.setSources(moe::SourceAllLegacy);
options->addOptionChaining("systemLog.syslogFacility",
"syslogFacility",
moe::String,
"syslog facility used for mongodb syslog message");
#endif // _WIN32
options->addOptionChaining("systemLog.logAppend",
"logappend",
moe::Switch,
"append to logpath instead of over-writing");
options->addOptionChaining("systemLog.logRotate",
"logRotate",
moe::String,
"set the log rotation behavior (rename|reopen)");
options->addOptionChaining("systemLog.timeStampFormat",
"timeStampFormat",
moe::String,
"Desired format for timestamps in log messages. One of ctime, "
"iso8601-utc or iso8601-local");
#if MONGO_ENTERPRISE_VERSION
options->addOptionChaining("security.redactClientLogData",
"redactClientLogData",
moe::Switch,
"Redact client data written to the diagnostics log");
#endif
options->addOptionChaining("processManagement.pidFilePath",
"pidfilepath",
moe::String,
"full path to pidfile (if not set, no pidfile is created)");
options->addOptionChaining("processManagement.timeZoneInfo",
"timeZoneInfo",
moe::String,
"full path to time zone info directory, e.g. /usr/share/zoneinfo");
options
->addOptionChaining(
"security.keyFile", "keyFile", moe::String, "private key for cluster authentication")
.incompatibleWith("noauth");
options->addOptionChaining("noauth", "noauth", moe::Switch, "run without security")
.setSources(moe::SourceAllLegacy)
.incompatibleWith("auth")
.incompatibleWith("keyFile")
.incompatibleWith("transitionToAuth")
.incompatibleWith("clusterAuthMode");
options
->addOptionChaining(
"setParameter", "setParameter", moe::StringMap, "Set a configurable parameter")
.composing();
options
->addOptionChaining(
"security.transitionToAuth",
"transitionToAuth",
moe::Switch,
"For rolling access control upgrade. Attempt to authenticate over outgoing "
"connections and proceed regardless of success. Accept incoming connections "
"with or without authentication.")
.incompatibleWith("noauth");
options
->addOptionChaining("security.clusterAuthMode",
"clusterAuthMode",
moe::String,
"Authentication mode used for cluster authentication. Alternatives are "
"(keyFile|sendKeyFile|sendX509|x509)")
.format("(:?keyFile)|(:?sendKeyFile)|(:?sendX509)|(:?x509)",
"(keyFile/sendKeyFile/sendX509/x509)");
#ifndef _WIN32
options
->addOptionChaining(
"nounixsocket", "nounixsocket", moe::Switch, "disable listening on unix sockets")
.setSources(moe::SourceAllLegacy);
options
->addOptionChaining(
"net.unixDomainSocket.enabled", "", moe::Bool, "disable listening on unix sockets")
.setSources(moe::SourceYAMLConfig);
options->addOptionChaining("net.unixDomainSocket.pathPrefix",
"unixSocketPrefix",
moe::String,
"alternative directory for UNIX domain sockets (defaults to /tmp)");
options->addOptionChaining("net.unixDomainSocket.filePermissions",
"filePermissions",
moe::Int,
unixSockPermsBuilder.str());
options->addOptionChaining(
"processManagement.fork", "fork", moe::Switch, "fork server process");
#endif
/* support for -vv -vvvv etc. */
for (string s = "vv"; s.length() <= 12; s.append("v")) {
options->addOptionChaining(s.c_str(), s.c_str(), moe::Switch, "verbose")
.hidden()
.setSources(moe::SourceAllLegacy);
}
options
->addOptionChaining("objcheck",
"objcheck",
moe::Switch,
"inspect client data for validity on receipt (DEFAULT)")
.hidden()
.setSources(moe::SourceAllLegacy)
.incompatibleWith("noobjcheck");
options
->addOptionChaining("noobjcheck",
"noobjcheck",
moe::Switch,
"do NOT inspect client data for validity on receipt")
.hidden()
.setSources(moe::SourceAllLegacy)
.incompatibleWith("objcheck");
options
->addOptionChaining("net.wireObjectCheck",
"",
moe::Bool,
"inspect client data for validity on receipt (DEFAULT)")
.hidden()
.setSources(moe::SourceYAMLConfig);
options
->addOptionChaining("systemLog.traceAllExceptions",
"traceExceptions",
moe::Switch,
"log stack traces for every exception")
.hidden();
options
->addOptionChaining("enableExperimentalStorageDetailsCmd",
"enableExperimentalStorageDetailsCmd",
moe::Switch,
"EXPERIMENTAL (UNSUPPORTED). "
"Enable command computing aggregate statistics on storage.")
.hidden()
.setSources(moe::SourceAllLegacy);
auto ret = addMessageCompressionOptions(options, false);
if (!ret.isOK()) {
return ret;
}
return Status::OK();
}
Status addWindowsServerOptions(moe::OptionSection* options) {
options->addOptionChaining("install", "install", moe::Switch, "install Windows service")
.setSources(moe::SourceAllLegacy);
options->addOptionChaining("remove", "remove", moe::Switch, "remove Windows service")
.setSources(moe::SourceAllLegacy);
options
->addOptionChaining(
"reinstall",
"reinstall",
moe::Switch,
"reinstall Windows service (equivalent to --remove followed by --install)")
.setSources(moe::SourceAllLegacy);
options->addOptionChaining("processManagement.windowsService.serviceName",
"serviceName",
moe::String,
"Windows service name");
options->addOptionChaining("processManagement.windowsService.displayName",
"serviceDisplayName",
moe::String,
"Windows service display name");
options->addOptionChaining("processManagement.windowsService.description",
"serviceDescription",
moe::String,
"Windows service description");
options->addOptionChaining("processManagement.windowsService.serviceUser",
"serviceUser",
moe::String,
"account for service execution");
options->addOptionChaining("processManagement.windowsService.servicePassword",
"servicePassword",
moe::String,
"password used to authenticate serviceUser");
options->addOptionChaining("service", "service", moe::Switch, "start mongodb service")
.hidden()
.setSources(moe::SourceAllLegacy);
return Status::OK();
}
namespace {
// Helpers for option storage
Status setupBinaryName(const std::vector& argv) {
if (argv.empty()) {
return Status(ErrorCodes::UnknownError, "Cannot get binary name: argv array is empty");
}
// setup binary name
serverGlobalParams.binaryName = argv[0];
size_t i = serverGlobalParams.binaryName.rfind('/');
if (i != string::npos) {
serverGlobalParams.binaryName = serverGlobalParams.binaryName.substr(i + 1);
}
return Status::OK();
}
Status setupCwd() {
// setup cwd
boost::system::error_code ec;
boost::filesystem::path cwd = boost::filesystem::current_path(ec);
if (ec) {
return Status(ErrorCodes::UnknownError,
"Cannot get current working directory: " + ec.message());
}
serverGlobalParams.cwd = cwd.string();
return Status::OK();
}
Status setArgvArray(const std::vector& argv) {
BSONArrayBuilder b;
std::vector censoredArgv = argv;
cmdline_utils::censorArgsVector(&censoredArgv);
for (size_t i = 0; i < censoredArgv.size(); i++) {
b << censoredArgv[i];
}
serverGlobalParams.argvArray = b.arr();
return Status::OK();
}
Status setParsedOpts(const moe::Environment& params) {
serverGlobalParams.parsedOpts = params.toBSON();
cmdline_utils::censorBSONObj(&serverGlobalParams.parsedOpts);
return Status::OK();
}
} // namespace
void printCommandLineOpts() {
log() << "options: " << serverGlobalParams.parsedOpts << endl;
}
Status validateServerOptions(const moe::Environment& params) {
if (params.count("verbose")) {
std::string verbosity = params["verbose"].as();
// Skip this for backwards compatibility. See SERVER-11471.
if (verbosity != "true") {
for (std::string::iterator iterator = verbosity.begin(); iterator != verbosity.end();
iterator++) {
if (*iterator != 'v') {
return Status(ErrorCodes::BadValue,
"The \"verbose\" option string cannot contain any characters "
"other than \"v\"");
}
}
}
}
#ifdef _WIN32
if (params.count("install") || params.count("reinstall")) {
if (params.count("logpath") &&
!boost::filesystem::path(params["logpath"].as()).is_absolute()) {
return Status(ErrorCodes::BadValue,
"logpath requires an absolute file path with Windows services");
}
if (params.count("config") &&
!boost::filesystem::path(params["config"].as()).is_absolute()) {
return Status(ErrorCodes::BadValue,
"config requires an absolute file path with Windows services");
}
if (params.count("processManagement.pidFilePath") &&
!boost::filesystem::path(params["processManagement.pidFilePath"].as())
.is_absolute()) {
return Status(ErrorCodes::BadValue,
"pidFilePath requires an absolute file path with Windows services");
}
if (params.count("security.keyFile") &&
!boost::filesystem::path(params["security.keyFile"].as()).is_absolute()) {
return Status(ErrorCodes::BadValue,
"keyFile requires an absolute file path with Windows services");
}
}
#endif
#ifdef MONGO_CONFIG_SSL
Status ret = validateSSLServerOptions(params);
if (!ret.isOK()) {
return ret;
}
#endif
bool haveAuthenticationMechanisms = true;
bool hasAuthorizationEnabled = false;
if (params.count("security.authenticationMechanisms") &&
params["security.authenticationMechanisms"].as>().empty()) {
haveAuthenticationMechanisms = false;
}
if (params.count("setParameter")) {
std::map parameters =
params["setParameter"].as>();
auto authMechParameter = parameters.find("authenticationMechanisms");
if (authMechParameter != parameters.end() && authMechParameter->second.empty()) {
haveAuthenticationMechanisms = false;
}
// Only register failpoint server parameters if enableTestCommands=1.
auto enableTestCommandsParameter = parameters.find("enableTestCommands");
if (enableTestCommandsParameter != parameters.end() &&
enableTestCommandsParameter->second.compare("1") == 0) {
getGlobalFailPointRegistry()->registerAllFailPointsAsServerParameters();
}
if (parameters.find("internalValidateFeaturesAsMaster") != parameters.end()) {
// Command line options that are disallowed when internalValidateFeaturesAsMaster is
// specified.
for (const auto& disallowedOption : {"replication.replSet", "master", "slave"}) {
if (params.count(disallowedOption)) {
return Status(ErrorCodes::BadValue,
str::stream()
<< "Cannot specify both internalValidateFeaturesAsMaster and "
<< disallowedOption);
}
}
}
}
if ((params.count("security.authorization") &&
params["security.authorization"].as() == "enabled") ||
params.count("security.clusterAuthMode") || params.count("security.keyFile") ||
params.count("auth")) {
hasAuthorizationEnabled = true;
}
if (hasAuthorizationEnabled && !haveAuthenticationMechanisms) {
return Status(ErrorCodes::BadValue,
"Authorization is enabled but no authentication mechanisms are present.");
}
return Status::OK();
}
Status canonicalizeServerOptions(moe::Environment* params) {
// "net.wireObjectCheck" comes from the config file, so override it if either "objcheck" or
// "noobjcheck" are set, since those come from the command line.
if (params->count("objcheck")) {
Status ret =
params->set("net.wireObjectCheck", moe::Value((*params)["objcheck"].as()));
if (!ret.isOK()) {
return ret;
}
ret = params->remove("objcheck");
if (!ret.isOK()) {
return ret;
}
}
if (params->count("noobjcheck")) {
Status ret =
params->set("net.wireObjectCheck", moe::Value(!(*params)["noobjcheck"].as()));
if (!ret.isOK()) {
return ret;
}
ret = params->remove("noobjcheck");
if (!ret.isOK()) {
return ret;
}
}
// "net.unixDomainSocket.enabled" comes from the config file, so override it if
// "nounixsocket" is set since that comes from the command line.
if (params->count("nounixsocket")) {
Status ret = params->set("net.unixDomainSocket.enabled",
moe::Value(!(*params)["nounixsocket"].as()));
if (!ret.isOK()) {
return ret;
}
ret = params->remove("nounixsocket");
if (!ret.isOK()) {
return ret;
}
}
// Handle both the "--verbose" string argument and the "-vvvv" arguments at the same time so
// that we ensure that we set the log level to the maximum of the options provided
int logLevel = -1;
for (std::string s = ""; s.length() <= 14; s.append("v")) {
if (!s.empty() && params->count(s) && (*params)[s].as() == true) {
logLevel = s.length();
}
if (params->count("verbose")) {
std::string verbosity;
params->get("verbose", &verbosity).transitional_ignore();
if (s == verbosity ||
// Treat a verbosity of "true" the same as a single "v". See SERVER-11471.
(s == "v" && verbosity == "true")) {
logLevel = s.length();
}
}
// Remove all "v" options we have already handled
Status ret = params->remove(s);
if (!ret.isOK()) {
return ret;
}
}
if (logLevel != -1) {
Status ret = params->set("systemLog.verbosity", moe::Value(logLevel));
if (!ret.isOK()) {
return ret;
}
ret = params->remove("verbose");
if (!ret.isOK()) {
return ret;
}
}
if (params->count("logpath")) {
std::string logpath;
Status ret = params->get("logpath", &logpath);
if (!ret.isOK()) {
return ret;
}
if (logpath.empty()) {
return Status(ErrorCodes::BadValue, "logpath cannot be empty if supplied");
}
ret = params->set("systemLog.destination", moe::Value(std::string("file")));
if (!ret.isOK()) {
return ret;
}
ret = params->set("systemLog.path", moe::Value(logpath));
if (!ret.isOK()) {
return ret;
}
ret = params->remove("logpath");
if (!ret.isOK()) {
return ret;
}
}
// "systemLog.destination" comes from the config file, so override it if "syslog" is set
// since that comes from the command line.
if (params->count("syslog") && (*params)["syslog"].as() == true) {
Status ret = params->set("systemLog.destination", moe::Value(std::string("syslog")));
if (!ret.isOK()) {
return ret;
}
ret = params->remove("syslog");
if (!ret.isOK()) {
return ret;
}
}
if (params->count("noauth")) {
Status ret =
params->set("security.authorization",
(*params)["noauth"].as() ? moe::Value(std::string("disabled"))
: moe::Value(std::string("enabled")));
if (!ret.isOK()) {
return ret;
}
ret = params->remove("noauth");
if (!ret.isOK()) {
return ret;
}
}
return Status::OK();
}
Status setupServerOptions(const std::vector& args) {
Status ret = setupBinaryName(args);
if (!ret.isOK()) {
return ret;
}
ret = setupCwd();
if (!ret.isOK()) {
return ret;
}
ret = setArgvArray(args);
if (!ret.isOK()) {
return ret;
}
return Status::OK();
}
Status storeServerOptions(const moe::Environment& params) {
Status ret = setParsedOpts(params);
if (!ret.isOK()) {
return ret;
}
if (params.count("systemLog.verbosity")) {
int verbosity = params["systemLog.verbosity"].as();
if (verbosity < 0) {
// This can only happen in YAML config
return Status(ErrorCodes::BadValue,
"systemLog.verbosity YAML Config cannot be negative");
}
logger::globalLogDomain()->setMinimumLoggedSeverity(logger::LogSeverity::Debug(verbosity));
}
// log component hierarchy verbosity levels
for (int i = 0; i < int(logger::LogComponent::kNumLogComponents); ++i) {
logger::LogComponent component = static_cast(i);
if (component == logger::LogComponent::kDefault) {
continue;
}
const string dottedName = "systemLog.component." + component.getDottedName() + ".verbosity";
if (params.count(dottedName)) {
int verbosity = params[dottedName].as();
// Clear existing log level if log level is negative.
if (verbosity < 0) {
logger::globalLogDomain()->clearMinimumLoggedSeverity(component);
} else {
logger::globalLogDomain()->setMinimumLoggedSeverity(
component, logger::LogSeverity::Debug(verbosity));
}
}
}
if (params.count("enableExperimentalStorageDetailsCmd")) {
serverGlobalParams.experimental.storageDetailsCmdEnabled =
params["enableExperimentalStorageDetailsCmd"].as();
}
if (params.count("net.port")) {
serverGlobalParams.port = params["net.port"].as();
}
if (params.count("net.ipv6") && params["net.ipv6"].as() == true) {
serverGlobalParams.enableIPv6 = true;
enableIPv6();
}
if (params.count("net.listenBacklog")) {
serverGlobalParams.listenBacklog = params["net.listenBacklog"].as();
}
if (params.count("net.transportLayer")) {
serverGlobalParams.transportLayer = params["net.transportLayer"].as();
if (serverGlobalParams.transportLayer != "asio" &&
serverGlobalParams.transportLayer != "legacy") {
return {ErrorCodes::BadValue,
"Unsupported value for transportLayer. Must be \"asio\" or \"legacy\""};
}
}
if (params.count("net.serviceExecutor")) {
auto value = params["net.serviceExecutor"].as();
if (serverGlobalParams.transportLayer == "legacy") {
if (value != "synchronous"_sd) {
return {ErrorCodes::BadValue,
"Unsupported value for serviceExecutor with the legacy transportLayer, "
"must be \"synchronous\""};
}
} else {
const auto valid = {"synchronous"_sd, "adaptive"_sd};
if (std::find(valid.begin(), valid.end(), value) == valid.end()) {
return {ErrorCodes::BadValue, "Unsupported value for serviceExecutor"};
}
}
serverGlobalParams.serviceExecutor = value;
} else {
serverGlobalParams.serviceExecutor = "synchronous";
}
if (params.count("security.transitionToAuth")) {
serverGlobalParams.transitionToAuth = params["security.transitionToAuth"].as();
}
if (params.count("security.clusterAuthMode")) {
std::string clusterAuthMode = params["security.clusterAuthMode"].as();
if (clusterAuthMode == "keyFile") {
serverGlobalParams.clusterAuthMode.store(ServerGlobalParams::ClusterAuthMode_keyFile);
} else if (clusterAuthMode == "sendKeyFile") {
serverGlobalParams.clusterAuthMode.store(
ServerGlobalParams::ClusterAuthMode_sendKeyFile);
} else if (clusterAuthMode == "sendX509") {
serverGlobalParams.clusterAuthMode.store(ServerGlobalParams::ClusterAuthMode_sendX509);
} else if (clusterAuthMode == "x509") {
serverGlobalParams.clusterAuthMode.store(ServerGlobalParams::ClusterAuthMode_x509);
} else {
return Status(ErrorCodes::BadValue,
"unsupported value for clusterAuthMode " + clusterAuthMode);
}
serverGlobalParams.authState = ServerGlobalParams::AuthState::kEnabled;
} else {
serverGlobalParams.clusterAuthMode.store(ServerGlobalParams::ClusterAuthMode_undefined);
}
if (params.count("systemLog.quiet")) {
serverGlobalParams.quiet.store(params["systemLog.quiet"].as());
}
if (params.count("systemLog.traceAllExceptions")) {
DBException::traceExceptions.store(params["systemLog.traceAllExceptions"].as());
}
if (params.count("net.maxIncomingConnections")) {
serverGlobalParams.maxConns = params["net.maxIncomingConnections"].as();
if (serverGlobalParams.maxConns < 5) {
return Status(ErrorCodes::BadValue, "maxConns has to be at least 5");
}
}
if (params.count("net.wireObjectCheck")) {
serverGlobalParams.objcheck = params["net.wireObjectCheck"].as();
}
if (params.count("net.bindIpAll") && params["net.bindIpAll"].as()) {
// Bind to all IP addresses
serverGlobalParams.bind_ip = "0.0.0.0";
if (params.count("net.ipv6") && params["net.ipv6"].as()) {
serverGlobalParams.bind_ip += ",::";
}
} else if (params.count("net.bindIp")) {
// Bind to enumerated IP addresses
serverGlobalParams.bind_ip = params["net.bindIp"].as();
} else {
// Bind to localhost
serverGlobalParams.bind_ip = "";
}
#ifndef _WIN32
if (params.count("net.unixDomainSocket.pathPrefix")) {
serverGlobalParams.socket = params["net.unixDomainSocket.pathPrefix"].as();
}
if (params.count("net.unixDomainSocket.enabled")) {
serverGlobalParams.noUnixSocket = !params["net.unixDomainSocket.enabled"].as();
}
if (params.count("net.unixDomainSocket.filePermissions")) {
serverGlobalParams.unixSocketPermissions =
params["net.unixDomainSocket.filePermissions"].as();
}
if ((params.count("processManagement.fork") &&
params["processManagement.fork"].as() == true) &&
(!params.count("shutdown") || params["shutdown"].as() == false)) {
serverGlobalParams.doFork = true;
}
#endif // _WIN32
if (params.count("systemLog.timeStampFormat")) {
using logger::MessageEventDetailsEncoder;
std::string formatterName = params["systemLog.timeStampFormat"].as();
if (formatterName == "ctime") {
MessageEventDetailsEncoder::setDateFormatter(outputDateAsCtime);
} else if (formatterName == "iso8601-utc") {
MessageEventDetailsEncoder::setDateFormatter(outputDateAsISOStringUTC);
} else if (formatterName == "iso8601-local") {
MessageEventDetailsEncoder::setDateFormatter(outputDateAsISOStringLocal);
} else {
StringBuilder sb;
sb << "Value of logTimestampFormat must be one of ctime, iso8601-utc "
<< "or iso8601-local; not \"" << formatterName << "\".";
return Status(ErrorCodes::BadValue, sb.str());
}
}
if (params.count("systemLog.destination")) {
std::string systemLogDestination = params["systemLog.destination"].as();
if (systemLogDestination == "file") {
if (params.count("systemLog.path")) {
serverGlobalParams.logpath = params["systemLog.path"].as();
} else {
return Status(ErrorCodes::BadValue,
"systemLog.path is required if systemLog.destination is to a "
"file");
}
} else if (systemLogDestination == "syslog") {
if (params.count("systemLog.path")) {
return Status(ErrorCodes::BadValue,
"Can only use systemLog.path if systemLog.destination is to a "
"file");
}
serverGlobalParams.logWithSyslog = true;
} else {
StringBuilder sb;
sb << "Bad value for systemLog.destination: " << systemLogDestination
<< ". Supported targets are: (syslog|file)";
return Status(ErrorCodes::BadValue, sb.str());
}
} else {
if (params.count("systemLog.path")) {
return Status(ErrorCodes::BadValue,
"Can only use systemLog.path if systemLog.destination is to a file");
}
}
#ifndef _WIN32
if (params.count("systemLog.syslogFacility")) {
std::string facility = params["systemLog.syslogFacility"].as();
bool set = false;
// match facility string to facility value
size_t facilitynamesLength = sizeof(facilitynames) / sizeof(facilitynames[0]);
for (unsigned long i = 0; i < facilitynamesLength && facilitynames[i].c_name != NULL; i++) {
if (!facility.compare(facilitynames[i].c_name)) {
serverGlobalParams.syslogFacility = facilitynames[i].c_val;
set = true;
}
}
if (!set) {
StringBuilder sb;
sb << "ERROR: syslogFacility must be set to a string representing one of the "
<< "possible syslog facilities";
return Status(ErrorCodes::BadValue, sb.str());
}
} else {
serverGlobalParams.syslogFacility = LOG_USER;
}
#endif // _WIN32
if (params.count("systemLog.logAppend") && params["systemLog.logAppend"].as() == true) {
serverGlobalParams.logAppend = true;
}
if (params.count("systemLog.logRotate")) {
std::string logRotateParam = params["systemLog.logRotate"].as();
if (logRotateParam == "reopen") {
serverGlobalParams.logRenameOnRotate = false;
if (serverGlobalParams.logAppend == false) {
return Status(ErrorCodes::BadValue,
"logAppend must equal true if logRotate is set to reopen");
}
} else if (logRotateParam == "rename") {
serverGlobalParams.logRenameOnRotate = true;
} else {
return Status(ErrorCodes::BadValue,
"unsupported value for logRotate " + logRotateParam);
}
}
if (!serverGlobalParams.logpath.empty() && serverGlobalParams.logWithSyslog) {
return Status(ErrorCodes::BadValue, "Cant use both a logpath and syslog ");
}
if (serverGlobalParams.doFork && serverGlobalParams.logpath.empty() &&
!serverGlobalParams.logWithSyslog) {
return Status(ErrorCodes::BadValue, "--fork has to be used with --logpath or --syslog");
}
if (params.count("security.keyFile")) {
serverGlobalParams.keyFile =
boost::filesystem::absolute(params["security.keyFile"].as()).generic_string();
serverGlobalParams.authState = ServerGlobalParams::AuthState::kEnabled;
}
if (serverGlobalParams.transitionToAuth ||
(params.count("security.authorization") &&
params["security.authorization"].as() == "disabled")) {
serverGlobalParams.authState = ServerGlobalParams::AuthState::kDisabled;
} else if (params.count("security.authorization") &&
params["security.authorization"].as() == "enabled") {
serverGlobalParams.authState = ServerGlobalParams::AuthState::kEnabled;
}
if (params.count("processManagement.pidFilePath")) {
serverGlobalParams.pidFile = params["processManagement.pidFilePath"].as();
}
if (params.count("processManagement.timeZoneInfo")) {
serverGlobalParams.timeZoneInfoPath = params["processManagement.timeZoneInfo"].as();
}
if (params.count("setParameter")) {
std::map parameters =
params["setParameter"].as>();
for (std::map::iterator parametersIt = parameters.begin();
parametersIt != parameters.end();
parametersIt++) {
ServerParameter* parameter =
mapFindWithDefault(ServerParameterSet::getGlobal()->getMap(),
parametersIt->first,
static_cast(NULL));
if (NULL == parameter) {
StringBuilder sb;
sb << "Illegal --setParameter parameter: \"" << parametersIt->first << "\"";
return Status(ErrorCodes::BadValue, sb.str());
}
if (!parameter->allowedToChangeAtStartup()) {
StringBuilder sb;
sb << "Cannot use --setParameter to set \"" << parametersIt->first
<< "\" at startup";
return Status(ErrorCodes::BadValue, sb.str());
}
Status status = parameter->setFromString(parametersIt->second);
if (!status.isOK()) {
StringBuilder sb;
sb << "Bad value for parameter \"" << parametersIt->first
<< "\": " << status.reason();
return Status(ErrorCodes::BadValue, sb.str());
}
}
}
if (!params.count("security.clusterAuthMode") && params.count("security.keyFile")) {
serverGlobalParams.clusterAuthMode.store(ServerGlobalParams::ClusterAuthMode_keyFile);
}
int clusterAuthMode = serverGlobalParams.clusterAuthMode.load();
if (serverGlobalParams.transitionToAuth &&
(clusterAuthMode != ServerGlobalParams::ClusterAuthMode_keyFile &&
clusterAuthMode != ServerGlobalParams::ClusterAuthMode_x509)) {
return Status(ErrorCodes::BadValue,
"--transitionToAuth must be used with keyFile or x509 authentication");
}
#ifdef MONGO_CONFIG_SSL
ret = storeSSLServerOptions(params);
if (!ret.isOK()) {
return ret;
}
#endif
ret = storeMessageCompressionOptions(params);
if (!ret.isOK()) {
return ret;
}
return Status::OK();
}
} // namespace mongo