diff options
author | Shaun Verch <shaun.verch@10gen.com> | 2013-08-14 11:54:01 -0400 |
---|---|---|
committer | Shaun Verch <shaun.verch@10gen.com> | 2013-09-05 13:49:35 -0400 |
commit | 03ca1e173f4ad480a817d542780035532a4efb0f (patch) | |
tree | c247110abd231bee71e20abc8f3cd4129fa6550c /src/mongo/db | |
parent | ea40937c304ad77884cc3087b491de502dca66b6 (diff) | |
download | mongo-03ca1e173f4ad480a817d542780035532a4efb0f.tar.gz |
SERVER-8510 Use new option parser in mongod and mongos and move parsing into MONGO_INITIALIZERS
Diffstat (limited to 'src/mongo/db')
-rw-r--r-- | src/mongo/db/cmdline.cpp | 541 | ||||
-rw-r--r-- | src/mongo/db/cmdline.h | 36 | ||||
-rw-r--r-- | src/mongo/db/cmdline_test.cpp | 48 | ||||
-rw-r--r-- | src/mongo/db/db.cpp | 414 | ||||
-rw-r--r-- | src/mongo/db/mongod_options.cpp | 367 | ||||
-rw-r--r-- | src/mongo/db/mongod_options.h | 30 | ||||
-rw-r--r-- | src/mongo/db/server_options.cpp | 293 | ||||
-rw-r--r-- | src/mongo/db/server_options.h | 34 |
8 files changed, 1206 insertions, 557 deletions
diff --git a/src/mongo/db/cmdline.cpp b/src/mongo/db/cmdline.cpp index 16e89d4c861..517e149b7b2 100644 --- a/src/mongo/db/cmdline.cpp +++ b/src/mongo/db/cmdline.cpp @@ -29,6 +29,9 @@ #include "mongo/util/map_util.h" #include "mongo/util/mongoutils/str.h" #include "mongo/util/net/listen.h" +#include "mongo/util/options_parser/environment.h" +#include "mongo/util/options_parser/option_section.h" +#include "mongo/util/options_parser/options_parser.h" #include "mongo/util/password.h" #ifdef _WIN32 @@ -39,10 +42,10 @@ #include <fstream> -namespace po = boost::program_options; - namespace mongo { + namespace moe = mongo::optionenvironment; + #ifdef _WIN32 string dbpath = "\\data\\db\\"; #else @@ -65,253 +68,227 @@ namespace { return parsedOpts; } - void CmdLine::addGlobalOptions( boost::program_options::options_description& general , - boost::program_options::options_description& hidden , - boost::program_options::options_description& ssl_options ) { - /* support for -vv -vvvv etc. */ - for (string s = "vv"; s.length() <= 12; s.append("v")) { - hidden.add_options()(s.c_str(), "verbose"); - } - - StringBuilder portInfoBuilder; - StringBuilder maxConnInfoBuilder; - - portInfoBuilder << "specify port number - " << DefaultDBPort << " by default"; - maxConnInfoBuilder << "max number of simultaneous connections - " << DEFAULT_MAX_CONN << " by default"; - - general.add_options() - ("help,h", "show this usage information") - ("version", "show version information") - ("config,f", po::value<string>(), "configuration file specifying additional options") - ("verbose,v", "be more verbose (include multiple times for more verbosity e.g. -vvvvv)") - ("quiet", "quieter output") - ("port", po::value<int>(), portInfoBuilder.str().c_str()) - ("bind_ip", po::value<string>(), "comma separated list of ip addresses to listen on - all local ips by default") - ("maxConns",po::value<int>(), maxConnInfoBuilder.str().c_str()) - ("logpath", po::value<string>() , "log file to send write to instead of stdout - has to be a file, not directory" ) - ("logappend" , "append to logpath instead of over-writing" ) - ("logTimestampFormat", po::value<string>(), "Desired format for timestamps in log " - "messages. One of ctime, iso8601-utc or iso8601-local") - ("pidfilepath", po::value<string>(), "full path to pidfile (if not set, no pidfile is created)") - ("keyFile", po::value<string>(), "private key for cluster authentication") - ("setParameter", po::value< std::vector<std::string> >()->composing(), - "Set a configurable parameter") - ("httpinterface", "enable http interface") - ("clusterAuthMode", po::value<std::string>(), - "Authentication mode used for cluster authentication." - " Alternatives are (keyfile|sendKeyfile|sendX509|x509)") -#ifndef _WIN32 - ("nounixsocket", "disable listening on unix sockets") - ("unixSocketPrefix", po::value<string>(), "alternative directory for UNIX domain sockets (defaults to /tmp)") - ("fork" , "fork server process" ) - ("syslog" , "log to system's syslog facility instead of file or stdout" ) -#endif - ; - + Status CmdLine::setupBinaryName(const std::vector<std::string>& argv) { -#ifdef MONGO_SSL - ssl_options.add_options() - ("sslOnNormalPorts" , "use ssl on configured ports" ) - ("sslPEMKeyFile" , po::value<string>(), "PEM file for ssl" ) - ("sslPEMKeyPassword" , po::value<string>()->implicit_value(""), - "PEM file password" ) - ("sslClusterFile", po::value<string>(), - "Key file for internal SSL authentication" ) - ("sslClusterPassword", po::value<string>()->implicit_value(""), - "Internal authentication key file password" ) - ("sslCAFile", po::value<std::string>(), - "Certificate Authority file for SSL") - ("sslCRLFile", po::value<std::string>(), - "Certificate Revocation List file for SSL") - ("sslWeakCertificateValidation", "allow client to connect without presenting a certificate") - ("sslFIPSMode", "activate FIPS 140-2 mode at startup") + if (argv.empty()) { + return Status(ErrorCodes::InternalError, "Cannot get binary name: argv array is empty"); + } + + // setup binary name + cmdLine.binaryName = argv[0]; + size_t i = cmdLine.binaryName.rfind( '/' ); + if ( i != string::npos ) { + cmdLine.binaryName = cmdLine.binaryName.substr( i + 1 ); + } + return Status::OK(); + } + + Status CmdLine::setupCwd() { + // setup cwd + char buffer[1024]; +#ifdef _WIN32 + verify( _getcwd( buffer , 1000 ) ); +#else + verify( getcwd( buffer , 1000 ) ); #endif - ; - - // Extra hidden options - hidden.add_options() - ("nohttpinterface", "disable http interface") - ("objcheck", "inspect client data for validity on receipt (DEFAULT)") - ("noobjcheck", "do NOT inspect client data for validity on receipt") - ("traceExceptions", "log stack traces for every exception") - ("enableExperimentalIndexStatsCmd", po::bool_switch(), - "EXPERIMENTAL (UNSUPPORTED). Enable command computing aggregate statistics on indexes.") - ("enableExperimentalStorageDetailsCmd", po::bool_switch(), - "EXPERIMENTAL (UNSUPPORTED). Enable command computing aggregate statistics on storage.") - ; + cmdLine.cwd = buffer; + return Status::OK(); } -#if defined(_WIN32) - void CmdLine::addWindowsOptions( boost::program_options::options_description& windows , - boost::program_options::options_description& hidden ) { - windows.add_options() - ("install", "install Windows service") - ("remove", "remove Windows service") - ("reinstall", "reinstall Windows service (equivalent to --remove followed by --install)") - ("serviceName", po::value<string>(), "Windows service name") - ("serviceDisplayName", po::value<string>(), "Windows service display name") - ("serviceDescription", po::value<string>(), "Windows service description") - ("serviceUser", po::value<string>(), "account for service execution") - ("servicePassword", po::value<string>(), "password used to authenticate serviceUser") - ; - hidden.add_options()("service", "start mongodb service"); + Status CmdLine::setArgvArray(const std::vector<std::string>& argv) { + BSONArrayBuilder b; + std::vector<std::string> censoredArgv = argv; + censor(&censoredArgv); + for (size_t i=0; i < censoredArgv.size(); i++) { + b << censoredArgv[i]; + } + argvArray = b.arr(); + return Status::OK(); } -#endif - bool CmdLine::parseConfigFile( istream &f, stringstream &ss ) { - string s; - char line[MAX_LINE_LENGTH]; +namespace { - while ( !f.eof() ) { - f.getline(line, MAX_LINE_LENGTH); - // Check if we failed to read from the stream for a reason other than eof - if ( f.fail() && !f.eof() ) { - return false; + // Converts a map of values with dotted key names to a BSONObj with sub objects. + // 1. Check for dotted field names and call valueMapToBSON recursively. + // 2. Append the actual value to our builder if we did not find a dot in our key name. + Status valueMapToBSON(const std::map<moe::Key, moe::Value>& params, + BSONObjBuilder* builder, + const std::string& prefix = std::string()) { + for (std::map<moe::Key, moe::Value>::const_iterator it(params.begin()); + it != params.end(); it++) { + moe::Key key = it->first; + moe::Value value = it->second; + + // 1. Check for dotted field names and call valueMapToBSON recursively. + // NOTE: this code depends on the fact that std::map is sorted + // + // EXAMPLE: + // The map: + // { + // "var1.dotted1" : false, + // "var2" : true, + // "var1.dotted2" : 6 + // } + // + // Gets sorted by keys as: + // { + // "var1.dotted1" : false, + // "var1.dotted2" : 6, + // "var2" : true + // } + // + // Which means when we see the "var1" prefix, we can iterate until we see either a name + // without a dot or without "var1" as a prefix, aggregating its fields in a new map as + // we go. Because the map is sorted, once we see a name without a dot or a "var1" + // prefix we know that we've seen everything with "var1" as a prefix and can recursively + // build the entire sub object at once using our new map (which is the only way to make + // a single coherent BSON sub object using this append only builder). + // + // The result of this function for this example should be a BSON object of the form: + // { + // "var1" : { + // "dotted1" : false, + // "dotted2" : 6 + // }, + // "var2" : true + // } + + // Check to see if this key name is dotted + std::string::size_type dotOffset = key.find('.'); + if (dotOffset != string::npos) { + + // Get the name of the "section" that we are currently iterating. This will be + // the name of our sub object. + std::string sectionName = key.substr(0, dotOffset); + + // Build a map of the "section" that we are iterating to be passed in a + // recursive call. + std::map<moe::Key, moe::Value> sectionMap; + + std::string beforeDot = key.substr(0, dotOffset); + std::string afterDot = key.substr(dotOffset + 1, key.size() - dotOffset - 1); + std::map<moe::Key, moe::Value>::const_iterator it_next = it; + + do { + // Here we know that the key at it_next has a dot and has the prefix we are + // currently creating a sub object for. Since that means we will definitely + // process that element in this loop, advance the outer for loop iterator here. + it = it_next; + + // Add the value to our section map with a key of whatever is after the dot + // since the section name itself will be part of our sub object builder. + sectionMap[afterDot] = value; + + // Peek at the next value for our iterator and check to see if we've finished. + if (++it_next == params.end()) { + break; + } + key = it_next->first; + value = it_next->second; + + // Look for a dot for our next iteration. + dotOffset = key.find('.'); + + beforeDot = key.substr(0, dotOffset); + afterDot = key.substr(dotOffset + 1, key.size() - dotOffset - 1); + } + while (dotOffset != string::npos && beforeDot == sectionName); + + // Use the section name in our object builder, and recursively call + // valueMapToBSON with our sub map with keys that have the section name removed. + BSONObjBuilder sectionObjBuilder(builder->subobjStart(sectionName)); + valueMapToBSON(sectionMap, §ionObjBuilder, sectionName); + sectionObjBuilder.done(); + + // Our iterator is currently on the last field that matched our dot and prefix, so + // continue to the next loop iteration. + continue; } - s = line; - std::remove(s.begin(), s.end(), ' '); - std::remove(s.begin(), s.end(), '\t'); - boost::to_upper(s); - - if ( s.find( "FASTSYNC" ) != string::npos ) - cout << "warning \"fastsync\" should not be put in your configuration file" << endl; - - if ( s.c_str()[0] == '#' ) { - // skipping commented line - } else if ( s.find( "=FALSE" ) == string::npos ) { - ss << line << endl; - } else { - cout << "warning: remove or comment out this line by starting it with \'#\', skipping now : " << line << endl; + + // 2. Append the actual value to our builder if we did not find a dot in our key name. + const type_info& type = value.type(); + + if (type == typeid(string)){ + if (value.as<string>().empty()) { + // boost po uses empty string for flags like --quiet + // TODO: Remove this when we remove boost::program_options + builder->appendBool(key, true); + } + else { + if ( _isPasswordArgument(key.c_str()) ) { + builder->append( key, "<password>" ); + } + else { + builder->append( key, value.as<string>() ); + } + } } + else if (type == typeid(int)) + builder->append(key, value.as<int>()); + else if (type == typeid(double)) + builder->append(key, value.as<double>()); + else if (type == typeid(bool)) + builder->appendBool(key, value.as<bool>()); + else if (type == typeid(long)) + builder->appendNumber(key, (long long)value.as<long>()); + else if (type == typeid(unsigned)) + builder->appendNumber(key, (long long)value.as<unsigned>()); + else if (type == typeid(unsigned long long)) + builder->appendNumber(key, (long long)value.as<unsigned long long>()); + else if (type == typeid(vector<string>)) + builder->append(key, value.as<vector<string> >()); + else + builder->append(key, "UNKNOWN TYPE: " + demangleName(type)); + } + return Status::OK(); + } +} // namespace + + Status CmdLine::setParsedOpts(moe::Environment& params) { + const std::map<moe::Key, moe::Value> paramsMap = params.getExplicitlySet(); + BSONObjBuilder builder; + Status ret = valueMapToBSON(paramsMap, &builder); + if (!ret.isOK()) { + return ret; } - return true; + parsedOpts = builder.obj(); + return Status::OK(); } - bool CmdLine::store( const std::vector<std::string>& argv, - boost::program_options::options_description& visible, - boost::program_options::options_description& hidden, - boost::program_options::positional_options_description& positional, - boost::program_options::variables_map ¶ms ) { + Status CmdLine::store( const std::vector<std::string>& argv, + moe::OptionSection& options, + moe::Environment& params ) { + Status ret = CmdLine::setupBinaryName(argv); + if (!ret.isOK()) { + return ret; + } - if (argv.empty()) - return false; + ret = CmdLine::setupCwd(); + if (!ret.isOK()) { + return ret; + } - { - // setup binary name - cmdLine.binaryName = argv[0]; - size_t i = cmdLine.binaryName.rfind( '/' ); - if ( i != string::npos ) - cmdLine.binaryName = cmdLine.binaryName.substr( i + 1 ); - - // setup cwd - char buffer[1024]; -#ifdef _WIN32 - verify( _getcwd( buffer , 1000 ) ); -#else - verify( getcwd( buffer , 1000 ) ); -#endif - cmdLine.cwd = buffer; - } - - - /* don't allow guessing - creates ambiguities when some options are - * prefixes of others. allow long disguises and don't allow guessing - * to get away with our vvvvvvv trick. */ - int style = (((po::command_line_style::unix_style ^ - po::command_line_style::allow_guessing) | - po::command_line_style::allow_long_disguise) ^ - po::command_line_style::allow_sticky); - - - try { - - po::options_description all; - all.add( visible ); - all.add( hidden ); - - po::store( po::command_line_parser(std::vector<std::string>(argv.begin() + 1, - argv.end())) - .options( all ) - .positional( positional ) - .style( style ) - .run(), - params ); - - if ( params.count("config") ) { - ifstream f( params["config"].as<string>().c_str() ); - if ( ! f.is_open() ) { - cout << "ERROR: could not read from config file" << endl << endl; - cout << visible << endl; - return false; - } + moe::OptionsParser parser; - stringstream ss; - if ( !CmdLine::parseConfigFile( f, ss ) ) { - cout << "ERROR: could not read from config file" << endl << endl; - cout << visible << endl; - return false; - } - po::store( po::parse_config_file( ss , all ) , params ); - f.close(); - } + // XXX: env is not used in the parser at this point, so just leave it empty + std::map<std::string, std::string> env; + + ret = parser.run(options, argv, env, ¶ms); + if (!ret.isOK()) { + std::cerr << "Error parsing command line: " << ret.toString() << std::endl; + std::cerr << "use --help for help" << std::endl; + return ret; } - catch (po::error &e) { - cout << "error command line: " << e.what() << endl; - cout << "use --help for help" << endl; - //cout << visible << endl; - return false; + + ret = CmdLine::setArgvArray(argv); + if (!ret.isOK()) { + return ret; } - { - BSONArrayBuilder b; - std::vector<std::string> censoredArgv = argv; - censor(&censoredArgv); - for (size_t i=0; i < censoredArgv.size(); i++) { - b << censoredArgv[i]; - } - argvArray = b.arr(); - } - - { - BSONObjBuilder b; - for (po::variables_map::const_iterator it(params.begin()), end(params.end()); it != end; it++){ - if (!it->second.defaulted()){ - const string& key = it->first; - const po::variable_value& value = it->second; - const type_info& type = value.value().type(); - - if (type == typeid(string)){ - if (value.as<string>().empty()) - b.appendBool(key, true); // boost po uses empty string for flags like --quiet - else { - if ( _isPasswordArgument(key.c_str()) ) { - b.append( key, "<password>" ); - } - else { - b.append( key, value.as<string>() ); - } - } - } - else if (type == typeid(int)) - b.append(key, value.as<int>()); - else if (type == typeid(double)) - b.append(key, value.as<double>()); - else if (type == typeid(bool)) - b.appendBool(key, value.as<bool>()); - else if (type == typeid(long)) - b.appendNumber(key, (long long)value.as<long>()); - else if (type == typeid(unsigned)) - b.appendNumber(key, (long long)value.as<unsigned>()); - else if (type == typeid(unsigned long long)) - b.appendNumber(key, (long long)value.as<unsigned long long>()); - else if (type == typeid(vector<string>)) - b.append(key, value.as<vector<string> >()); - else - b.append(key, "UNKNOWN TYPE: " + demangleName(type)); - } - } - parsedOpts = b.obj(); + ret = CmdLine::setParsedOpts(params); + if (!ret.isOK()) { + return ret; } if (params.count("verbose")) { @@ -356,8 +333,7 @@ namespace { cmdLine.maxConns = params["maxConns"].as<int>(); if ( cmdLine.maxConns < 5 ) { - out() << "maxConns has to be at least 5" << endl; - return false; + return Status(ErrorCodes::BadValue, "maxConns has to be at least 5"); } } @@ -366,8 +342,7 @@ namespace { } if (params.count("noobjcheck")) { if (params.count("objcheck")) { - out() << "can't have both --objcheck and --noobjcheck" << endl; - return false; + return Status(ErrorCodes::BadValue, "can't have both --objcheck and --noobjcheck"); } cmdLine.objcheck = false; } @@ -407,29 +382,27 @@ namespace { MessageEventDetailsEncoder::setDateFormatter(dateToISOStringLocal); } else { - cout << "Value of logTimestampFormat must be one of ctime, iso8601-utc or " - "iso8601-local; not \"" << formatterName << "\"." << endl; - return false; + 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("logpath")) { cmdLine.logpath = params["logpath"].as<string>(); if (cmdLine.logpath.empty()) { - cout << "logpath cannot be empty if supplied" << endl; - return false; + return Status(ErrorCodes::BadValue, "logpath cannot be empty if supplied"); } } cmdLine.logWithSyslog = params.count("syslog"); cmdLine.logAppend = params.count("logappend"); if (!cmdLine.logpath.empty() && cmdLine.logWithSyslog) { - cout << "Cant use both a logpath and syslog " << endl; - return false; + return Status(ErrorCodes::BadValue, "Cant use both a logpath and syslog "); } if (cmdLine.doFork && cmdLine.logpath.empty() && !cmdLine.logWithSyslog) { - cout << "--fork has to be used with --logpath or --syslog" << endl; - return false; + return Status(ErrorCodes::BadValue, "--fork has to be used with --logpath or --syslog"); } if (params.count("keyFile")) { @@ -447,27 +420,29 @@ namespace { std::string name; std::string value; if (!mongoutils::str::splitOn(parameters[i], '=', name, value)) { - cout << "Illegal option assignment: \"" << parameters[i] << "\"" << endl; - return false; + StringBuilder sb; + sb << "Illegal option assignment: \"" << parameters[i] << "\""; + return Status(ErrorCodes::BadValue, sb.str()); } ServerParameter* parameter = mapFindWithDefault( ServerParameterSet::getGlobal()->getMap(), name, static_cast<ServerParameter*>(NULL)); if (NULL == parameter) { - cout << "Illegal --setParameter parameter: \"" << name << "\"" << endl; - return false; + StringBuilder sb; + sb << "Illegal --setParameter parameter: \"" << name << "\""; + return Status(ErrorCodes::BadValue, sb.str()); } if (!parameter->allowedToChangeAtStartup()) { - cout << "Cannot use --setParameter to set \"" << name << "\" at startup" << - endl; - return false; + StringBuilder sb; + sb << "Cannot use --setParameter to set \"" << name << "\" at startup"; + return Status(ErrorCodes::BadValue, sb.str()); } Status status = parameter->setFromString(value); if (!status.isOK()) { - cout << "Bad value for parameter \"" << name << "\": " << status.reason() - << endl; - return false; + StringBuilder sb; + sb << "Bad value for parameter \"" << name << "\": " << status.reason(); + return Status(ErrorCodes::BadValue, sb.str()); } } } @@ -477,50 +452,49 @@ namespace { #ifdef MONGO_SSL - if (params.count("sslPEMKeyFile")) { - cmdLine.sslPEMKeyFile = params["sslPEMKeyFile"].as<string>(); + if (params.count("ssl.PEMKeyFile")) { + cmdLine.sslPEMKeyFile = params["ssl.PEMKeyFile"].as<string>(); } - if (params.count("sslPEMKeyPassword")) { - cmdLine.sslPEMKeyPassword = params["sslPEMKeyPassword"].as<string>(); + if (params.count("ssl.PEMKeyPassword")) { + cmdLine.sslPEMKeyPassword = params["ssl.PEMKeyPassword"].as<string>(); } - if (params.count("sslClusterFile")) { - cmdLine.sslClusterFile = params["sslClusterFile"].as<string>(); + if (params.count("ssl.clusterFile")) { + cmdLine.sslClusterFile = params["ssl.clusterFile"].as<string>(); } - if (params.count("sslClusterPassword")) { - cmdLine.sslClusterPassword = params["sslClusterPassword"].as<string>(); + if (params.count("ssl.clusterPassword")) { + cmdLine.sslClusterPassword = params["ssl.clusterPassword"].as<string>(); } - if (params.count("sslCAFile")) { - cmdLine.sslCAFile = params["sslCAFile"].as<std::string>(); + if (params.count("ssl.CAFile")) { + cmdLine.sslCAFile = params["ssl.CAFile"].as<std::string>(); } - if (params.count("sslCRLFile")) { - cmdLine.sslCRLFile = params["sslCRLFile"].as<std::string>(); + if (params.count("ssl.CRLFile")) { + cmdLine.sslCRLFile = params["ssl.CRLFile"].as<std::string>(); } - if (params.count("sslWeakCertificateValidation")) { + if (params.count("ssl.weakCertificateValidation")) { cmdLine.sslWeakCertificateValidation = true; } - if (params.count("sslOnNormalPorts")) { + if (params.count("ssl.sslOnNormalPorts")) { cmdLine.sslOnNormalPorts = true; if ( cmdLine.sslPEMKeyFile.size() == 0 ) { - log() << "need sslPEMKeyFile with sslOnNormalPorts" << endl; - return false; + return Status(ErrorCodes::BadValue, + "need sslPEMKeyFile with sslOnNormalPorts"); } if (cmdLine.sslWeakCertificateValidation && cmdLine.sslCAFile.empty()) { - log() << "need sslCAFile with sslWeakCertificateValidation" << endl; - return false; + return Status(ErrorCodes::BadValue, + "need sslCAFile with sslWeakCertificateValidation"); } if (!cmdLine.sslCRLFile.empty() && cmdLine.sslCAFile.empty()) { - log() << "need sslCAFile with sslCRLFile" << endl; - return false; + return Status(ErrorCodes::BadValue, "need sslCAFile with sslCRLFile"); } - if (params.count("sslFIPSMode")) { + if (params.count("ssl.FIPSMode")) { cmdLine.sslFIPSMode = true; } } @@ -532,35 +506,36 @@ namespace { cmdLine.sslCRLFile.size() || cmdLine.sslWeakCertificateValidation || cmdLine.sslFIPSMode) { - log() << "need to enable sslOnNormalPorts" << endl; - return false; + return Status(ErrorCodes::BadValue, "need to enable sslOnNormalPorts"); } if (cmdLine.clusterAuthMode == "sendKeyfile" || cmdLine.clusterAuthMode == "sendX509" || cmdLine.clusterAuthMode == "x509") { if (!cmdLine.sslOnNormalPorts){ - log() << "need to enable sslOnNormalPorts" << endl; - return false; + return Status(ErrorCodes::BadValue, "need to enable sslOnNormalPorts"); } } else if (params.count("clusterAuthMode") && cmdLine.clusterAuthMode != "keyfile") { - log() << "unsupported value for clusterAuthMode " << cmdLine.clusterAuthMode << endl; - return false; + StringBuilder sb; + sb << "unsupported value for clusterAuthMode " << cmdLine.clusterAuthMode; + return Status(ErrorCodes::BadValue, sb.str()); } #else // ifdef MONGO_SSL // Keyfile is currently the only supported value if not using SSL if (params.count("clusterAuthMode") && cmdLine.clusterAuthMode != "keyfile") { - log() << "unsupported value for clusterAuthMode " << cmdLine.clusterAuthMode << endl; - return false; + StringBuilder sb; + sb << "unsupported value for clusterAuthMode " << cmdLine.clusterAuthMode; + return Status(ErrorCodes::BadValue, sb.str()); } #endif - return true; + return Status::OK(); } static bool _isPasswordArgument(const char* argumentName) { static const char* const passwordArguments[] = { "sslPEMKeyPassword", + "ssl.PEMKeyPassword", "servicePassword", NULL // Last entry sentinel. }; diff --git a/src/mongo/db/cmdline.h b/src/mongo/db/cmdline.h index ac1801d6890..4d4d0030a05 100644 --- a/src/mongo/db/cmdline.h +++ b/src/mongo/db/cmdline.h @@ -19,20 +19,18 @@ #include <string> #include <vector> +#include "mongo/base/status.h" #include "mongo/db/jsobj.h" #include "mongo/platform/process_id.h" #include "mongo/util/net/listen.h" -namespace boost { - namespace program_options { - class options_description; - class positional_options_description; - class variables_map; - } -} - namespace mongo { + namespace optionenvironment { + class OptionSection; + class Environment; + } // namespace optionenvironment + /* command line options */ /* concurrency: OK/READ */ @@ -160,23 +158,12 @@ namespace mongo { static void launchOk(); - static void addGlobalOptions( boost::program_options::options_description& general , - boost::program_options::options_description& hidden , - boost::program_options::options_description& ssl_options ); - - static void addWindowsOptions( boost::program_options::options_description& windows , - boost::program_options::options_description& hidden ); - - - static bool parseConfigFile( istream &f, std::stringstream &ss); /** * @return true if should run program, false if should exit */ - static bool store( const std::vector<std::string>& argv, - boost::program_options::options_description& visible, - boost::program_options::options_description& hidden, - boost::program_options::positional_options_description& positional, - boost::program_options::variables_map &output ); + static Status store( const std::vector<std::string>& argv, + optionenvironment::OptionSection& options, + optionenvironment::Environment& output ); /** * Blot out sensitive fields in the argv array. @@ -187,6 +174,11 @@ namespace mongo { static BSONArray getArgvArray(); static BSONObj getParsedOpts(); + static Status setupBinaryName(const std::vector<std::string>& argv); + static Status setupCwd(); + static Status setArgvArray(const std::vector<std::string>& argv); + static Status setParsedOpts(optionenvironment::Environment& params); + time_t started; }; diff --git a/src/mongo/db/cmdline_test.cpp b/src/mongo/db/cmdline_test.cpp index 108ea228bf1..8955adbec51 100644 --- a/src/mongo/db/cmdline_test.cpp +++ b/src/mongo/db/cmdline_test.cpp @@ -19,7 +19,9 @@ #include <vector> #include "mongo/db/cmdline.h" +#include "mongo/db/jsobj.h" #include "mongo/unittest/unittest.h" +#include "mongo/util/options_parser/environment.h" namespace mongo { @@ -27,6 +29,8 @@ namespace mongo { namespace { + namespace moe = mongo::optionenvironment; + void testCensoringArgv(const char* const * expected, const char* const * toCensor, int elementCount) { @@ -220,5 +224,49 @@ namespace { testCensoringVector(expected, argv, argc); } + TEST(ParsedOptsTests, NormalValues) { + moe::Environment environment; + ASSERT_OK(environment.set(moe::Key("val1"), moe::Value(6))); + ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(std::string("string")))); + ASSERT_OK(CmdLine::setParsedOpts(environment)); + BSONObj obj = BSON( "val1" << 6 << "val2" << "string" ); + // TODO: Put a comparison here that doesn't depend on the field order. Right now it is + // based on the sort order of keys in a std::map. + ASSERT_EQUALS(obj, CmdLine::getParsedOpts()); + } + + TEST(ParsedOptsTests, DottedValues) { + moe::Environment environment; + ASSERT_OK(environment.set(moe::Key("val1.dotted1"), moe::Value(6))); + ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(true))); + ASSERT_OK(environment.set(moe::Key("val1.dotted2"), moe::Value(std::string("string")))); + ASSERT_OK(CmdLine::setParsedOpts(environment)); + BSONObj obj = BSON( "val1" << BSON( "dotted1" << 6 << "dotted2" << "string" ) + << "val2" << true ); + // TODO: Put a comparison here that doesn't depend on the field order. Right now it is + // based on the sort order of keys in a std::map. + ASSERT_EQUALS(obj, CmdLine::getParsedOpts()); + } + + TEST(ParsedOptsTests, DeepDottedValues) { + moe::Environment environment; + ASSERT_OK(environment.set(moe::Key("val1.first1.second1.third1"), moe::Value(6))); + ASSERT_OK(environment.set(moe::Key("val1.first1.second2.third1"), moe::Value(false))); + ASSERT_OK(environment.set(moe::Key("val1.first2"), moe::Value(std::string("string")))); + ASSERT_OK(environment.set(moe::Key("val1.first1.second1.third2"), moe::Value(true))); + ASSERT_OK(environment.set(moe::Key("val2"), moe::Value(6.0))); + ASSERT_OK(CmdLine::setParsedOpts(environment)); + BSONObj obj = BSON( "val1" << BSON( "first1" << + BSON( "second1" << + BSON( "third1" << 6 << "third2" << true ) << + "second2" << + BSON( "third1" << false ) ) << + "first2" << "string" ) << + "val2" << 6.0 ); + // TODO: Put a comparison here that doesn't depend on the field order. Right now it is + // based on the sort order of keys in a std::map. + ASSERT_EQUALS(obj, CmdLine::getParsedOpts()); + } + } // namespace } // namespace mongo diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp index b3f11d5b7dc..b4888277077 100644 --- a/src/mongo/db/db.cpp +++ b/src/mongo/db/db.cpp @@ -45,6 +45,7 @@ #include "mongo/db/introspect.h" #include "mongo/db/json.h" #include "mongo/db/kill_current_op.h" +#include "mongo/db/mongod_options.h" #include "mongo/db/pdfile.h" #include "mongo/db/query/internal_plans.h" #include "mongo/db/range_deleter_service.h" @@ -66,6 +67,8 @@ #include "mongo/util/net/message_server.h" #include "mongo/util/net/ssl_manager.h" #include "mongo/util/ntservice.h" +#include "mongo/util/options_parser/environment.h" +#include "mongo/util/options_parser/option_section.h" #include "mongo/util/ramlog.h" #include "mongo/util/stacktrace.h" #include "mongo/util/startup_test.h" @@ -103,6 +106,8 @@ namespace mongo { #endif CmdLine cmdLine; + moe::Environment params; + moe::OptionSection options("Allowed options"); static bool scriptingEnabled = true; bool shouldRepairDatabases = 0; static bool forceRepair = 0; @@ -781,12 +786,8 @@ namespace mongo { using namespace mongo; -#include <boost/program_options.hpp> - -namespace po = boost::program_options; - -void show_help_text(po::options_description options) { - cout << options << endl; +void show_help_text(const moe::OptionSection& options) { + std::cout << options.helpString() << std::endl; }; static int mongoDbMain(int argc, char* argv[], char** envp); @@ -809,147 +810,23 @@ int main(int argc, char* argv[], char** envp) { } #endif -static void buildOptionsDescriptions(po::options_description *pVisible, - po::options_description *pHidden, - po::positional_options_description *pPositional) { - - po::options_description& visible_options = *pVisible; - po::options_description& hidden_options = *pHidden; - po::positional_options_description& positional_options = *pPositional; - - po::options_description general_options("General options"); -#if defined(_WIN32) - po::options_description windows_scm_options("Windows Service Control Manager options"); -#endif - po::options_description ms_options("Master/slave options (old; use replica sets instead)"); - po::options_description rs_options("Replica set options"); - po::options_description replication_options("Replication options"); - po::options_description sharding_options("Sharding options"); - po::options_description hidden_sharding_options("Sharding options"); - po::options_description ssl_options("SSL options"); - - CmdLine::addGlobalOptions( general_options , hidden_options , ssl_options ); - - StringBuilder dbpathBuilder; - dbpathBuilder << "directory for datafiles - defaults to " << dbpath; - - general_options.add_options() - ("auth", "run with security") - ("cpu", "periodically show cpu and iowait utilization") - ("dbpath", po::value<string>() , dbpathBuilder.str().c_str()) - ("diaglog", po::value<int>(), "0=off 1=W 2=R 3=both 7=W+some reads") - ("directoryperdb", "each database will be stored in a separate directory") - ("ipv6", "enable IPv6 support (disabled by default)") - ("journal", "enable journaling") - ("journalCommitInterval", po::value<unsigned>(), "how often to group/batch commit (ms)") - ("journalOptions", po::value<int>(), "journal diagnostic options") - ("jsonp","allow JSONP access via http (has security implications)") - ("noauth", "run without security") - ("noIndexBuildRetry", "don't retry any index builds that were interrupted by shutdown") - ("nojournal", "disable journaling (journaling is on by default for 64 bit)") - ("noprealloc", "disable data file preallocation - will often hurt performance") - ("noscripting", "disable scripting engine") - ("notablescan", "do not allow table scans") - ("nssize", po::value<int>()->default_value(16), ".ns file size (in MB) for new databases") - ("profile",po::value<int>(), "0=off 1=slow, 2=all") - ("quota", "limits each database to a certain number of files (8 default)") - ("quotaFiles", po::value<int>(), "number of files allowed per db, requires --quota") - ("repair", "run repair on all dbs") - ("repairpath", po::value<string>() , "root directory for repair files - defaults to dbpath" ) - ("rest","turn on simple rest api") -#if defined(__linux__) - ("shutdown", "kill a running server (for init scripts)") -#endif - ("slowms",po::value<int>()->default_value(100), "value of slow for profile and console log" ) - ("smallfiles", "use a smaller default file size") - ("syncdelay",po::value<double>()->default_value(60), "seconds between disk syncs (0=never, but not recommended)") - ("sysinfo", "print some diagnostic system information") - ("upgrade", "upgrade db if needed") - ; - -#if defined(_WIN32) - CmdLine::addWindowsOptions( windows_scm_options, hidden_options ); -#endif - - replication_options.add_options() - ("oplogSize", po::value<int>(), "size to use (in MB) for replication op log. default is 5% of disk space (i.e. large is good)") - ; - - ms_options.add_options() - ("master", "master mode") - ("slave", "slave mode") - ("source", po::value<string>(), "when slave: specify master as <server:port>") - ("only", po::value<string>(), "when slave: specify a single database to replicate") - ("slavedelay", po::value<int>(), "specify delay (in seconds) to be used when applying master ops to slave") - ("autoresync", "automatically resync if slave data is stale") - ; - - rs_options.add_options() - ("replSet", po::value<string>(), "arg is <setname>[/<optionalseedhostlist>]") - ("replIndexPrefetch", po::value<string>(), "specify index prefetching behavior (if secondary) [none|_id_only|all]") - ; - - sharding_options.add_options() - ("configsvr", "declare this is a config db of a cluster; default port 27019; default dir /data/configdb") - ("shardsvr", "declare this is a shard db of a cluster; default port 27018") - ; - - hidden_sharding_options.add_options() - ("noMoveParanoia" , "turn off paranoid saving of data for the moveChunk command; default" ) - ("moveParanoia" , "turn on paranoid saving of data during the moveChunk command (used for internal system diagnostics)" ) - ; - hidden_options.add(hidden_sharding_options); - - hidden_options.add_options() - ("fastsync", "indicate that this instance is starting from a dbpath snapshot of the repl peer") - ("pretouch", po::value<int>(), "n pretouch threads for applying master/slave operations") - ("command", po::value< vector<string> >(), "command") - ("cacheSize", po::value<long>(), "cache size (in MB) for rec store") - ("nodur", "disable journaling") - // things we don't want people to use - ("nohints", "ignore query hints") - ("nopreallocj", "don't preallocate journal files") - ("dur", "enable journaling") // old name for --journal - ("durOptions", po::value<int>(), "durability diagnostic options") // deprecated name - // deprecated pairing command line options - ("pairwith", "DEPRECATED") - ("arbiter", "DEPRECATED") - ("opIdMem", "DEPRECATED") - ; - - positional_options.add("command", 3); - visible_options.add(general_options); -#if defined(_WIN32) - visible_options.add(windows_scm_options); -#endif - visible_options.add(replication_options); - visible_options.add(ms_options); - visible_options.add(rs_options); - visible_options.add(sharding_options); -#ifdef MONGO_SSL - visible_options.add(ssl_options); -#endif -} - -static void processCommandLineOptions(const std::vector<std::string>& argv) { - po::options_description visible_options("Allowed options"); - po::options_description hidden_options("Hidden options"); - po::positional_options_description positional_options; - buildOptionsDescriptions(&visible_options, &hidden_options, &positional_options); +static Status processCommandLineOptions(const std::vector<std::string>& argv) { + Status ret = addMongodOptions(&options); + if (!ret.isOK()) { + StringBuilder sb; + sb << "Error getting mongod options descriptions: " << ret.toString(); + return Status(ErrorCodes::InternalError, sb.str()); + } { - po::variables_map params; - - if (!CmdLine::store(argv, - visible_options, - hidden_options, - positional_options, - params)) { - ::_exit(EXIT_FAILURE); + ret = CmdLine::store(argv, options, params); + if (!ret.isOK()) { + std::cerr << "Error parsing command line: " << ret.toString() << std::endl; + ::_exit(EXIT_BADOPTIONS); } if (params.count("help")) { - show_help_text(visible_options); + std::cout << options.helpString() << std::endl; ::_exit(EXIT_SUCCESS); } if (params.count("version")) { @@ -1013,7 +890,7 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { } if( params.count("dur") || params.count( "journal" ) ) { if (journalExplicit) { - log() << "Can't specify both --journal and --nojournal options." << endl; + std::cerr << "Can't specify both --journal and --nojournal options." << std::endl; ::_exit(EXIT_BADOPTIONS); } journalExplicit = true; @@ -1027,8 +904,8 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { // ie no point making life a little more complex by giving an error on a dev environment. cmdLine.journalCommitInterval = params["journalCommitInterval"].as<unsigned>(); if( cmdLine.journalCommitInterval <= 1 || cmdLine.journalCommitInterval > 300 ) { - out() << "--journalCommitInterval out of allowed range (0-300ms)" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "--journalCommitInterval out of allowed range (0-300ms)" << std::endl; + ::_exit(EXIT_BADOPTIONS); } } if (params.count("journalOptions")) { @@ -1037,13 +914,14 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { if (params.count("repairpath")) { repairpath = params["repairpath"].as<string>(); if (!repairpath.size()) { - out() << "repairpath is empty" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "repairpath is empty" << std::endl; + ::_exit(EXIT_BADOPTIONS); } if (cmdLine.dur && !str::startsWith(repairpath, dbpath)) { - out() << "You must use a --repairpath that is a subdirectory of --dbpath when using journaling" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "You must use a --repairpath that is a subdirectory of " + << "--dbpath when using journaling" << std::endl; + ::_exit(EXIT_BADOPTIONS); } } if (params.count("nohints")) { @@ -1054,8 +932,8 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { } if (params.count("httpinterface")) { if (params.count("nohttpinterface")) { - log() << "can't have both --httpinterface and --nohttpinterface" << endl; - ::_exit( EXIT_BADOPTIONS ); + std::cerr << "can't have both --httpinterface and --nohttpinterface" << std::endl; + ::_exit(EXIT_BADOPTIONS); } cmdLine.isHttpInterfaceEnabled = true; } @@ -1101,14 +979,14 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { if (params.count("diaglog")) { int x = params["diaglog"].as<int>(); if ( x < 0 || x > 7 ) { - out() << "can't interpret --diaglog setting" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "can't interpret --diaglog setting" << std::endl; + ::_exit(EXIT_BADOPTIONS); } _diaglog.setLevel(x); } if (params.count("repair")) { if (journalExplicit && cmdLine.dur) { - log() << "Can't specify both --journal and --repair options." << endl; + std::cerr << "Can't specify both --journal and --repair options." << std::endl; ::_exit(EXIT_BADOPTIONS); } @@ -1139,9 +1017,10 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { if (params.count("autoresync")) { replSettings.autoresync = true; if( params.count("replSet") ) { - out() << "--autoresync is not used with --replSet" << endl; - out() << "see http://dochub.mongodb.org/core/resyncingaverystalereplicasetmember" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "--autoresync is not used with --replSet\nsee " + << "http://dochub.mongodb.org/core/resyncingaverystalereplicasetmember" + << std::endl; + ::_exit(EXIT_BADOPTIONS); } } if (params.count("source")) { @@ -1153,12 +1032,12 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { } if (params.count("replSet")) { if (params.count("slavedelay")) { - out() << "--slavedelay cannot be used with --replSet" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "--slavedelay cannot be used with --replSet" << std::endl; + ::_exit(EXIT_BADOPTIONS); } else if (params.count("only")) { - out() << "--only cannot be used with --replSet" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "--only cannot be used with --replSet" << std::endl; + ::_exit(EXIT_BADOPTIONS); } /* seed list of hosts for the repl set */ cmdLine._replSet = params["replSet"].as<string>().c_str(); @@ -1175,8 +1054,8 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { if( params.count("nssize") ) { int x = params["nssize"].as<int>(); if (x <= 0 || x > (0x7fffffff/1024/1024)) { - out() << "bad --nssize arg" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "bad --nssize arg" << std::endl; + ::_exit(EXIT_BADOPTIONS); } lenForNewNsFiles = x * 1024 * 1024; verify(lenForNewNsFiles > 0); @@ -1184,13 +1063,16 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { if (params.count("oplogSize")) { long long x = params["oplogSize"].as<int>(); if (x <= 0) { - out() << "bad --oplogSize arg" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "bad --oplogSize arg" << std::endl; + ::_exit(EXIT_BADOPTIONS); } // note a small size such as x==1 is ok for an arbiter. if( x > 1000 && sizeof(void*) == 4 ) { - out() << "--oplogSize of " << x << "MB is too big for 32 bit version. Use 64 bit build instead." << endl; - dbexit( EXIT_BADOPTIONS ); + StringBuilder sb; + std::cerr << "--oplogSize of " << x + << "MB is too big for 32 bit version. Use 64 bit build instead." + << std::endl; + ::_exit(EXIT_BADOPTIONS); } cmdLine.oplogSize = x * 1024 * 1024; verify(cmdLine.oplogSize > 0); @@ -1198,10 +1080,11 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { if (params.count("cacheSize")) { long x = params["cacheSize"].as<long>(); if (x <= 0) { - out() << "bad --cacheSize arg" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "bad --cacheSize arg" << std::endl; + ::_exit(EXIT_BADOPTIONS); } - log() << "--cacheSize option not currently supported" << endl; + std::cerr << "--cacheSize option not currently supported" << std::endl; + ::_exit(EXIT_BADOPTIONS); } if (params.count("port") == 0 ) { if( params.count("configsvr") ) { @@ -1209,16 +1092,16 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { } if( params.count("shardsvr") ) { if( params.count("configsvr") ) { - log() << "can't do --shardsvr and --configsvr at the same time" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "can't do --shardsvr and --configsvr at the same time" << std::endl; + ::_exit(EXIT_BADOPTIONS); } cmdLine.port = CmdLine::ShardServerPort; } } else { if ( cmdLine.port <= 0 || cmdLine.port > 65535 ) { - out() << "bad --port number" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "bad --port number" << std::endl; + ::_exit(EXIT_BADOPTIONS); } } if ( params.count("configsvr" ) ) { @@ -1226,8 +1109,8 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { cmdLine.smallfiles = true; // config server implies small files dur::DataLimitPerJournalFile = 128 * 1024 * 1024; if (cmdLine.usingReplSets() || replSettings.master || replSettings.slave) { - log() << "replication should not be enabled on a config server" << endl; - ::_exit(-1); + std::cerr << "replication should not be enabled on a config server" << std::endl; + ::_exit(EXIT_BADOPTIONS); } if ( params.count( "nodur" ) == 0 && params.count( "nojournal" ) == 0 ) cmdLine.dur = true; @@ -1245,8 +1128,9 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { } if (params.count("noMoveParanoia") > 0 && params.count("moveParanoia") > 0) { - out() << "The moveParanoia and noMoveParanoia flags cannot both be set; please use only one of them." << endl; - ::_exit( EXIT_BADOPTIONS ); + std::cerr << "The moveParanoia and noMoveParanoia flags cannot both be set; " + << "please use only one of them." << std::endl; + ::_exit(EXIT_BADOPTIONS); } if (params.count("noMoveParanoia")) @@ -1256,104 +1140,132 @@ static void processCommandLineOptions(const std::vector<std::string>& argv) { cmdLine.moveParanoia = true; if (params.count("pairwith") || params.count("arbiter") || params.count("opIdMem")) { - out() << "****" << endl; - out() << "Replica Pairs have been deprecated. Invalid options: --pairwith, --arbiter, and/or --opIdMem" << endl; - out() << "<http://dochub.mongodb.org/core/replicapairs>" << endl; - out() << "****" << endl; - dbexit( EXIT_BADOPTIONS ); + std::cerr << "****\n" + << "Replica Pairs have been deprecated. Invalid options: --pairwith, " + << "--arbiter, and/or --opIdMem\n" + << "<http://dochub.mongodb.org/core/replicapairs>\n" + << "****" << std::endl; + ::_exit(EXIT_BADOPTIONS); } // needs to be after things like --configsvr parsing, thus here. if( repairpath.empty() ) repairpath = dbpath; - // The "command" option is deprecated. For backward compatibility, still support the "run" - // and "dbppath" command. The "run" command is the same as just running mongod, so just - // falls through. - if (params.count("command")) { - vector<string> command = params["command"].as< vector<string> >(); - - if (command[0].compare("dbpath") == 0) { - cout << dbpath << endl; - ::_exit(EXIT_SUCCESS); - } - - if (command[0].compare("run") != 0) { - cout << "Invalid command: " << command[0] << endl; - cout << visible_options << endl; - ::_exit(EXIT_FAILURE); - } - - if (command.size() > 1) { - cout << "Too many parameters to 'run' command" << endl; - cout << visible_options << endl; - ::_exit(EXIT_FAILURE); - } - } - if( cmdLine.pretouch ) log() << "--pretouch " << cmdLine.pretouch << endl; - if (sizeof(void*) == 4 && !journalExplicit){ + if (sizeof(void*) == 4 && !journalExplicit) { // trying to make this stand out more like startup warnings log() << endl; warning() << "32-bit servers don't have journaling enabled by default. Please use --journal if you want durability." << endl; log() << endl; } + } + + return Status::OK(); +} + +MONGO_INITIALIZER_GENERAL(ParseStartupConfiguration, + ("GlobalLogManager"), + ("default", "completedStartupConfig"))(InitializerContext* context) { + + Status ret = processCommandLineOptions(context->args()); + if (!ret.isOK()) { + return ret; + } + + return Status::OK(); +} + +MONGO_INITIALIZER_GENERAL(ForkServerOrDie, + ("completedStartupConfig"), + ("default"))(InitializerContext* context) { + mongo::forkServerOrDie(); + return Status::OK(); +} + +/* + * This function should contain the startup "actions" that we take based on the startup config. It + * is intended to separate the actions from "storage" and "validation" of our startup configuration. + */ +static void startupConfigActions(const std::vector<std::string>& argv) { + // The "command" option is deprecated. For backward compatibility, still support the "run" + // and "dbppath" command. The "run" command is the same as just running mongod, so just + // falls through. + if (params.count("command")) { + vector<string> command = params["command"].as< vector<string> >(); + + if (command[0].compare("dbpath") == 0) { + cout << dbpath << endl; + ::_exit(EXIT_SUCCESS); + } + + if (command[0].compare("run") != 0) { + cout << "Invalid command: " << command[0] << endl; + show_help_text(options); + ::_exit(EXIT_FAILURE); + } + + if (command.size() > 1) { + cout << "Too many parameters to 'run' command" << endl; + show_help_text(options); + ::_exit(EXIT_FAILURE); + } + } #ifdef _WIN32 - ntservice::configureService(initService, - params, - defaultServiceStrings, - std::vector<std::string>(), - argv); + ntservice::configureService(initService, + params, + defaultServiceStrings, + std::vector<std::string>(), + argv); #endif // _WIN32 #ifdef __linux__ - if (params.count("shutdown")){ - bool failed = false; - - string name = ( boost::filesystem::path( dbpath ) / "mongod.lock" ).string(); - if ( !boost::filesystem::exists( name ) || boost::filesystem::file_size( name ) == 0 ) - failed = true; - - pid_t pid; - string procPath; - if (!failed){ - try { - ifstream f (name.c_str()); - f >> pid; - procPath = (str::stream() << "/proc/" << pid); - if (!boost::filesystem::exists(procPath)) - failed = true; - } - catch (const std::exception& e){ - cerr << "Error reading pid from lock file [" << name << "]: " << e.what() << endl; + if (params.count("shutdown")){ + bool failed = false; + + string name = ( boost::filesystem::path( dbpath ) / "mongod.lock" ).string(); + if ( !boost::filesystem::exists( name ) || boost::filesystem::file_size( name ) == 0 ) + failed = true; + + pid_t pid; + string procPath; + if (!failed){ + try { + ifstream f (name.c_str()); + f >> pid; + procPath = (str::stream() << "/proc/" << pid); + if (!boost::filesystem::exists(procPath)) failed = true; - } } - - if (failed) { - cerr << "There doesn't seem to be a server running with dbpath: " << dbpath << endl; - ::_exit(EXIT_FAILURE); + catch (const std::exception& e){ + cerr << "Error reading pid from lock file [" << name << "]: " << e.what() << endl; + failed = true; } + } - cout << "killing process with pid: " << pid << endl; - int ret = kill(pid, SIGTERM); - if (ret) { - int e = errno; - cerr << "failed to kill process: " << errnoWithDescription(e) << endl; - ::_exit(EXIT_FAILURE); - } + if (failed) { + cerr << "There doesn't seem to be a server running with dbpath: " << dbpath << endl; + ::_exit(EXIT_FAILURE); + } - while (boost::filesystem::exists(procPath)) { - sleepsecs(1); - } + cout << "killing process with pid: " << pid << endl; + int ret = kill(pid, SIGTERM); + if (ret) { + int e = errno; + cerr << "failed to kill process: " << errnoWithDescription(e) << endl; + ::_exit(EXIT_FAILURE); + } - ::_exit(EXIT_SUCCESS); + while (boost::filesystem::exists(procPath)) { + sleepsecs(1); } -#endif + + ::_exit(EXIT_SUCCESS); } +#endif } MONGO_INITIALIZER_GENERAL(CreateAuthorizationManager, @@ -1399,10 +1311,8 @@ static int mongoDbMain(int argc, char* argv[], char **envp) { if( argc == 1 ) cout << dbExecCommand << " --help for help and startup options" << endl; - - processCommandLineOptions(std::vector<std::string>(argv, argv + argc)); - mongo::forkServerOrDie(); mongo::runGlobalInitializersOrDie(argc, argv, envp); + startupConfigActions(std::vector<std::string>(argv, argv + argc)); CmdLine::censor(argc, argv); if (!initializeServerGlobalState()) diff --git a/src/mongo/db/mongod_options.cpp b/src/mongo/db/mongod_options.cpp new file mode 100644 index 00000000000..5b4d877062e --- /dev/null +++ b/src/mongo/db/mongod_options.cpp @@ -0,0 +1,367 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "mongo/db/mongod_options.h" + +#include <string> +#include <vector> + +#include "mongo/base/status.h" +#include "mongo/bson/util/builder.h" +#include "mongo/db/server_options.h" +#include "mongo/util/options_parser/option_description.h" +#include "mongo/util/options_parser/option_section.h" + +namespace mongo { + + typedef moe::OptionDescription OD; + typedef moe::PositionalOptionDescription POD; + + extern std::string dbpath; + + Status addMongodOptions(moe::OptionSection* options) { + + moe::OptionSection general_options("General options"); + + Status ret = addGeneralServerOptions(&general_options); + if (!ret.isOK()) { + return ret; + } + +#if defined(_WIN32) + moe::OptionSection windows_scm_options("Windows Service Control Manager options"); + + ret = addWindowsServerOptions(&windows_scm_options); + if (!ret.isOK()) { + return ret; + } +#endif + +#ifdef MONGO_SSL + moe::OptionSection ssl_options("SSL options"); + + ret = addSSLServerOptions(&ssl_options); + if (!ret.isOK()) { + return ret; + } +#endif + + moe::OptionSection ms_options("Master/slave options (old; use replica sets instead)"); + moe::OptionSection rs_options("Replica set options"); + moe::OptionSection replication_options("Replication options"); + moe::OptionSection sharding_options("Sharding options"); + + StringBuilder dbpathBuilder; + dbpathBuilder << "directory for datafiles - defaults to " << dbpath; + + ret = general_options.addOption(OD("auth", "auth", moe::Switch, "run with security", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("cpu", "cpu", moe::Switch, + "periodically show cpu and iowait utilization", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("dbpath", "dbpath", moe::String, + dbpathBuilder.str().c_str(), true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("diaglog", "diaglog", moe::Int, + "0=off 1=W 2=R 3=both 7=W+some reads", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("directoryperdb", "directoryperdb", moe::Switch, + "each database will be stored in a separate directory", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("ipv6", "ipv6", moe::Switch, + "enable IPv6 support (disabled by default)", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("journal", "journal", moe::Switch, "enable journaling", + true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("journalCommitInterval", "journalCommitInterval", + moe::Unsigned, "how often to group/batch commit (ms)", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("journalOptions", "journalOptions", moe::Int, + "journal diagnostic options", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("jsonp", "jsonp", moe::Switch, + "allow JSONP access via http (has security implications)", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("noauth", "noauth", moe::Switch, "run without security", + true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("noIndexBuildRetry", "noIndexBuildRetry", moe::Switch, + "don't retry any index builds that were interrupted by shutdown", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("nojournal", "nojournal", moe::Switch, + "disable journaling (journaling is on by default for 64 bit)", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("noprealloc", "noprealloc", moe::Switch, + "disable data file preallocation - will often hurt performance", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("noscripting", "noscripting", moe::Switch, + "disable scripting engine", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("notablescan", "notablescan", moe::Switch, + "do not allow table scans", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("nssize", "nssize", moe::Int, + ".ns file size (in MB) for new databases", true, moe::Value(16))); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("profile", "profile", moe::Int, "0=off 1=slow, 2=all", + true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("quota", "quota", moe::Switch, + "limits each database to a certain number of files (8 default)", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("quotaFiles", "quotaFiles", moe::Int, + "number of files allowed per db, requires --quota", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("repair", "repair", moe::Switch, "run repair on all dbs", + true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("repairpath", "repairpath", moe::String, + "root directory for repair files - defaults to dbpath" , true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("rest", "rest", moe::Switch, "turn on simple rest api", + true)); + if (!ret.isOK()) { + return ret; + } +#if defined(__linux__) + ret = general_options.addOption(OD("shutdown", "shutdown", moe::Switch, + "kill a running server (for init scripts)", true)); + if (!ret.isOK()) { + return ret; + } +#endif + ret = general_options.addOption(OD("slowms", "slowms", moe::Int, + "value of slow for profile and console log" , true, moe::Value(100))); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("smallfiles", "smallfiles", moe::Switch, + "use a smaller default file size", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("syncdelay", "syncdelay", moe::Double, + "seconds between disk syncs (0=never, but not recommended)", true, + moe::Value(60.0))); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("sysinfo", "sysinfo", moe::Switch, + "print some diagnostic system information", true)); + if (!ret.isOK()) { + return ret; + } + ret = general_options.addOption(OD("upgrade", "upgrade", moe::Switch, + "upgrade db if needed", true)); + if (!ret.isOK()) { + return ret; + } + + ret = replication_options.addOption(OD("oplogSize", "oplogSize", moe::Int, + "size to use (in MB) for replication op log. default is 5% of disk space " + "(i.e. large is good)", true)); + if (!ret.isOK()) { + return ret; + } + + ret = ms_options.addOption(OD("master", "master", moe::Switch, "master mode", true)); + if (!ret.isOK()) { + return ret; + } + ret = ms_options.addOption(OD("slave", "slave", moe::Switch, "slave mode", true)); + if (!ret.isOK()) { + return ret; + } + ret = ms_options.addOption(OD("source", "source", moe::String, + "when slave: specify master as <server:port>", true)); + if (!ret.isOK()) { + return ret; + } + ret = ms_options.addOption(OD("only", "only", moe::String, + "when slave: specify a single database to replicate", true)); + if (!ret.isOK()) { + return ret; + } + ret = ms_options.addOption(OD("slavedelay", "slavedelay", moe::Int, + "specify delay (in seconds) to be used when applying master ops to slave", + true)); + if (!ret.isOK()) { + return ret; + } + ret = ms_options.addOption(OD("autoresync", "autoresync", moe::Switch, + "automatically resync if slave data is stale", true)); + if (!ret.isOK()) { + return ret; + } + + ret = rs_options.addOption(OD("replSet", "replSet", moe::String, + "arg is <setname>[/<optionalseedhostlist>]", true)); + if (!ret.isOK()) { + return ret; + } + ret = rs_options.addOption(OD("replIndexPrefetch", "replIndexPrefetch", moe::String, + "specify index prefetching behavior (if secondary) [none|_id_only|all]", true)); + if (!ret.isOK()) { + return ret; + } + + ret = sharding_options.addOption(OD("configsvr", "configsvr", moe::Switch, + "declare this is a config db of a cluster; default port 27019; " + "default dir /data/configdb", true)); + if (!ret.isOK()) { + return ret; + } + ret = sharding_options.addOption(OD("shardsvr", "shardsvr", moe::Switch, + "declare this is a shard db of a cluster; default port 27018", true)); + if (!ret.isOK()) { + return ret; + } + + ret = sharding_options.addOption(OD("noMoveParanoia", "noMoveParanoia", moe::Switch, + "turn off paranoid saving of data for the moveChunk command; default", false)); + if (!ret.isOK()) { + return ret; + } + ret = sharding_options.addOption(OD("moveParanoia", "moveParanoia", moe::Switch, + "turn on paranoid saving of data during the moveChunk command " + "(used for internal system diagnostics)", false)); + if (!ret.isOK()) { + return ret; + } + options->addSection(general_options); +#if defined(_WIN32) + options->addSection(windows_scm_options); +#endif + options->addSection(replication_options); + options->addSection(ms_options); + options->addSection(rs_options); + options->addSection(sharding_options); +#ifdef MONGO_SSL + options->addSection(ssl_options); +#endif + + ret = options->addOption(OD("fastsync", "fastsync", moe::Switch, + "indicate that this instance is starting from a " + "dbpath snapshot of the repl peer", false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("pretouch", "pretouch", moe::Int, + "n pretouch threads for applying master/slave operations", false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("command", "command", moe::StringVector, "command", false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("cacheSize", "cacheSize", moe::Long, + "cache size (in MB) for rec store", false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("nodur", "nodur", moe::Switch, "disable journaling", false)); + if (!ret.isOK()) { + return ret; + } + // things we don't want people to use + ret = options->addOption(OD("nohints", "nohints", moe::Switch, "ignore query hints", + false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("nopreallocj", "nopreallocj", moe::Switch, + "don't preallocate journal files", false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("dur", "dur", moe::Switch, "enable journaling", false)); + if (!ret.isOK()) { + return ret; + } // old name for --journal + ret = options->addOption(OD("durOptions", "durOptions", moe::Int, + "durability diagnostic options", false)); + if (!ret.isOK()) { + return ret; + } // deprecated name + // deprecated pairing command line options + ret = options->addOption(OD("pairwith", "pairwith", moe::Switch, "DEPRECATED", false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("arbiter", "arbiter", moe::Switch, "DEPRECATED", false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("opIdMem", "opIdMem", moe::Switch, "DEPRECATED", false)); + if (!ret.isOK()) { + return ret; + } + + ret = options->addPositionalOption(POD("command", moe::String, 3)); + if (!ret.isOK()) { + return ret; + } + + return Status::OK(); + } + +} // namespace mongo diff --git a/src/mongo/db/mongod_options.h b/src/mongo/db/mongod_options.h new file mode 100644 index 00000000000..f87850ab2b7 --- /dev/null +++ b/src/mongo/db/mongod_options.h @@ -0,0 +1,30 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "mongo/base/status.h" + +namespace mongo { + + namespace optionenvironment { + class OptionSection; + } // namespace optionenvironment + + namespace moe = mongo::optionenvironment; + + Status addMongodOptions(moe::OptionSection* options); +} diff --git a/src/mongo/db/server_options.cpp b/src/mongo/db/server_options.cpp new file mode 100644 index 00000000000..0e00d096220 --- /dev/null +++ b/src/mongo/db/server_options.cpp @@ -0,0 +1,293 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#include "mongo/db/server_options.h" + +#include "mongo/base/status.h" +#include "mongo/bson/util/builder.h" +#include "mongo/db/cmdline.h" // For CmdLine::DefaultDBPort +#include "mongo/util/net/listen.h" // For DEFAULT_MAX_CONN +#include "mongo/util/options_parser/option_description.h" +#include "mongo/util/options_parser/option_section.h" + +namespace mongo { + + typedef moe::OptionDescription OD; + typedef moe::PositionalOptionDescription POD; + + Status addGeneralServerOptions(moe::OptionSection* options) { + StringBuilder portInfoBuilder; + StringBuilder maxConnInfoBuilder; + + portInfoBuilder << "specify port number - " << CmdLine::DefaultDBPort << " by default"; + maxConnInfoBuilder << "max number of simultaneous connections - " + << DEFAULT_MAX_CONN << " by default"; + + Status ret = options->addOption(OD("help", "help,h", moe::Switch, + "show this usage information", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("version", "version", moe::Switch, "show version information", + true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("config", "config,f", moe::String, + "configuration file specifying additional options", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("verbose", "verbose,v", moe::Switch, + "be more verbose (include multiple times for more verbosity e.g. -vvvvv)", + true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("quiet", "quiet", moe::Switch, "quieter output", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("port", "port", moe::Int, portInfoBuilder.str().c_str(), true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("bind_ip", "bind_ip", moe::String, + "comma separated list of ip addresses to listen on - all local ips by default", + true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("maxConns", "maxConns", moe::Int, + maxConnInfoBuilder.str().c_str(), true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("logpath", "logpath", moe::String, + "log file to send write to instead of stdout - has to be a file, not directory", + true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("logappend", "logappend", moe::Switch, + "append to logpath instead of over-writing", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("logTimestampFormat", "logTimestampFormat", moe::String, + "Desired format for timestamps in log messages. One of ctime, " + "iso8601-utc or iso8601-local", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("pidfilepath", "pidfilepath", moe::String, + "full path to pidfile (if not set, no pidfile is created)", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("keyFile", "keyFile", moe::String, + "private key for cluster authentication", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("setParameter", "setParameter", moe::StringVector, + "Set a configurable parameter", true, moe::Value(), moe::Value(), true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("httpinterface", "httpinterface", moe::Switch, + "enable http interface", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("clusterAuthMode", "clusterAuthMode", moe::String, + "Authentication mode used for cluster authentication. Alternatives are " + "(keyfile|sendKeyfile|sendX509|x509)", true)); + if (!ret.isOK()) { + return ret; + } +#ifndef _WIN32 + ret = options->addOption(OD("nounixsocket", "nounixsocket", moe::Switch, + "disable listening on unix sockets", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("unixSocketPrefix", "unixSocketPrefix", moe::String, + "alternative directory for UNIX domain sockets (defaults to /tmp)", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("fork", "fork", moe::Switch, "fork server process", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("syslog", "syslog", moe::Switch, + "log to system's syslog facility instead of file or stdout", true)); + if (!ret.isOK()) { + return ret; + } +#endif + + /* support for -vv -vvvv etc. */ + for (string s = "vv"; s.length() <= 12; s.append("v")) { + ret = options->addOption(OD(s.c_str(), s.c_str(), moe::Switch, "verbose", false)); + if(!ret.isOK()) { + return ret; + } + } + + // Extra hidden options + ret = options->addOption(OD("nohttpinterface", "nohttpinterface", moe::Switch, + "disable http interface", false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("objcheck", "objcheck", moe::Switch, + "inspect client data for validity on receipt (DEFAULT)", false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("noobjcheck", "noobjcheck", moe::Switch, + "do NOT inspect client data for validity on receipt", false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("traceExceptions", "traceExceptions", moe::Switch, + "log stack traces for every exception", false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("enableExperimentalIndexStatsCmd", + "enableExperimentalIndexStatsCmd", moe::Switch, + "EXPERIMENTAL (UNSUPPORTED). " + "Enable command computing aggregate statistics on indexes.", false)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("enableExperimentalStorageDetailsCmd", + "enableExperimentalStorageDetailsCmd", moe::Switch, + "EXPERIMENTAL (UNSUPPORTED). " + "Enable command computing aggregate statistics on storage.", false)); + if (!ret.isOK()) { + return ret; + } + + return Status::OK(); + } + + Status addWindowsServerOptions(moe::OptionSection* options) { + Status ret = options->addOption(OD("install", "install", moe::Switch, + "install Windows service", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("remove", "remove", moe::Switch, "remove Windows service", + true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("reinstall", "reinstall", moe::Switch, + "reinstall Windows service (equivalent to --remove followed by --install)", + true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("serviceName", "serviceName", moe::String, + "Windows service name", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("serviceDisplayName", "serviceDisplayName", moe::String, + "Windows service display name", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("serviceDescription", "serviceDescription", moe::String, + "Windows service description", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("serviceUser", "serviceUser", moe::String, + "account for service execution", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("servicePassword", "servicePassword", moe::String, + "password used to authenticate serviceUser", true)); + if (!ret.isOK()) { + return ret; + } + + ret = options->addOption(OD("service", "service", moe::Switch, "start mongodb service", + false)); + if (!ret.isOK()) { + return ret; + } + + return Status::OK(); + } + + Status addSSLServerOptions(moe::OptionSection* options) { + Status ret = options->addOption(OD("ssl.sslOnNormalPorts", "sslOnNormalPorts", moe::Switch, + "use ssl on configured ports", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("ssl.PEMKeyFile", "sslPEMKeyFile", moe::String, + "PEM file for ssl" , true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("ssl.PEMKeyPassword", "sslPEMKeyPassword", moe::String, + "PEM file password" , true, moe::Value(), moe::Value(std::string("")))); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("ssl.clusterFile", "sslClusterFile", moe::String, + "Key file for internal SSL authentication" , true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("ssl.clusterPassword", "sslClusterPassword", moe::String, + "Internal authentication key file password" , true, moe::Value(), moe::Value(std::string("")))); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("ssl.CAFile", "sslCAFile", moe::String, + "Certificate Authority file for SSL", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("ssl.CRLFile", "sslCRLFile", moe::String, + "Certificate Revocation List file for SSL", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("ssl.weakCertificateValidation", "sslWeakCertificateValidation", + moe::Switch, "allow client to connect without presenting a certificate", true)); + if (!ret.isOK()) { + return ret; + } + ret = options->addOption(OD("ssl.FIPSMode", "sslFIPSMode", moe::Switch, + "activate FIPS 140-2 mode at startup", true)); + if (!ret.isOK()) { + return ret; + } + + return Status::OK(); + } + +} // namespace mongo diff --git a/src/mongo/db/server_options.h b/src/mongo/db/server_options.h new file mode 100644 index 00000000000..1320c422cd3 --- /dev/null +++ b/src/mongo/db/server_options.h @@ -0,0 +1,34 @@ +/* + * 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 <http://www.gnu.org/licenses/>. + */ + +#pragma once + +#include "mongo/base/status.h" + +namespace mongo { + + namespace optionenvironment { + class OptionSection; + } // namespace optionenvironment + + namespace moe = mongo::optionenvironment; + + Status addGeneralServerOptions(moe::OptionSection* options); + + Status addWindowsServerOptions(moe::OptionSection* options); + + Status addSSLServerOptions(moe::OptionSection* options); +} |