summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenrik Edin <henrik.edin@mongodb.com>2018-04-03 10:29:48 -0400
committerHenrik Edin <henrik.edin@mongodb.com>2018-04-10 10:41:36 -0400
commitcb2b7de230a656986553e99f4a9f3a64f6be8a1e (patch)
treecf185762899c6c513aa66eb814fa5688b6cdac82
parentfb9aed12d2ab29884f2567ae9e60e021790823bd (diff)
downloadmongo-cb2b7de230a656986553e99f4a9f3a64f6be8a1e.tar.gz
SERVER-32487 Embedded CAPI takes a yaml config string instead of argc and argv.
-rw-r--r--src/mongo/client/embedded/SConscript10
-rw-r--r--src/mongo/client/embedded/embedded.cpp10
-rw-r--r--src/mongo/client/embedded/embedded.h2
-rw-r--r--src/mongo/client/embedded/embedded_options.cpp6
-rw-r--r--src/mongo/client/embedded/embedded_options_parser_init.cpp57
-rw-r--r--src/mongo/client/embedded/embedded_transport_layer_test.cpp21
-rw-r--r--src/mongo/client/embedded/libmongodbcapi.cpp35
-rw-r--r--src/mongo/client/embedded/libmongodbcapi.h10
-rw-r--r--src/mongo/client/embedded/libmongodbcapi_test.cpp24
-rw-r--r--src/mongo/util/options_parser/options_parser.cpp66
-rw-r--r--src/mongo/util/options_parser/options_parser.h13
11 files changed, 178 insertions, 76 deletions
diff --git a/src/mongo/client/embedded/SConscript b/src/mongo/client/embedded/SConscript
index 369ff49dcb0..1130e37cdc6 100644
--- a/src/mongo/client/embedded/SConscript
+++ b/src/mongo/client/embedded/SConscript
@@ -41,7 +41,6 @@ env.Library(
'$BUILD_DIR/mongo/db/storage/storage_engine_lock_file',
'$BUILD_DIR/mongo/db/storage/storage_engine_metadata',
'$BUILD_DIR/mongo/db/storage/storage_options',
- '$BUILD_DIR/mongo/util/options_parser/options_parser_init',
'service_entry_point_embedded',
],
)
@@ -61,6 +60,7 @@ env.Library(
source=[
'embedded_options.cpp',
'embedded_options_init.cpp',
+ 'embedded_options_parser_init.cpp',
],
LIBDEPS=[
'$BUILD_DIR/mongo/db/server_options',
@@ -147,7 +147,9 @@ if get_option('install-mode') == 'hygienic':
],
)
-capiTest = env.Program(
+capiTestEnv = env.Clone()
+capiTestEnv.InjectThirdPartyIncludePaths(libraries=['yaml'])
+capiTest = capiTestEnv.Program(
target='mongo_embedded_capi_test',
source=[
'libmongodbcapi_test.cpp',
@@ -204,7 +206,9 @@ if get_option('install-mode') == 'hygienic':
],
)
-embeddedTransportTest = env.Program(
+embeddedTransportTestEnv = env.Clone()
+embeddedTransportTestEnv.InjectThirdPartyIncludePaths(libraries=['yaml'])
+embeddedTransportTest = embeddedTransportTestEnv.Program(
target='mongo_embedded_transport_test',
source=[
'embedded_transport_layer_test.cpp',
diff --git a/src/mongo/client/embedded/embedded.cpp b/src/mongo/client/embedded/embedded.cpp
index 955b221d0f3..328217bd157 100644
--- a/src/mongo/client/embedded/embedded.cpp
+++ b/src/mongo/client/embedded/embedded.cpp
@@ -167,11 +167,17 @@ void shutdown(ServiceContext* srvContext) {
}
-ServiceContext* initialize(int argc, char* argv[], char** envp) {
+ServiceContext* initialize(const char* yaml_config) {
srand(static_cast<unsigned>(curTimeMicros64()));
setGlobalServiceContext(createServiceContext());
- Status status = mongo::runGlobalInitializers(argc, argv, envp, getGlobalServiceContext());
+
+ // yaml_config is passed to the options parser through the argc/argv interface that already
+ // existed. If it is nullptr then use 0 count which will be interpreted as empty string.
+ const char* argv[2] = {yaml_config, nullptr};
+
+ Status status =
+ mongo::runGlobalInitializers(yaml_config ? 1 : 0, argv, nullptr, getGlobalServiceContext());
uassertStatusOKWithContext(status, "Global initilization failed");
Client::initThread("initandlisten");
diff --git a/src/mongo/client/embedded/embedded.h b/src/mongo/client/embedded/embedded.h
index 714c6c1c90a..8601b4e709a 100644
--- a/src/mongo/client/embedded/embedded.h
+++ b/src/mongo/client/embedded/embedded.h
@@ -34,7 +34,7 @@ namespace mongo {
class ServiceContext;
namespace embedded {
-ServiceContext* initialize(int argc, char* argv[], char** envp);
+ServiceContext* initialize(const char* yaml_config);
void shutdown(ServiceContext* serviceContext);
} // namespace embedded
} // namespace mongo
diff --git a/src/mongo/client/embedded/embedded_options.cpp b/src/mongo/client/embedded/embedded_options.cpp
index f47f771d3f7..8d1096a2300 100644
--- a/src/mongo/client/embedded/embedded_options.cpp
+++ b/src/mongo/client/embedded/embedded_options.cpp
@@ -52,8 +52,10 @@ Status addOptions(optionenvironment::OptionSection* options) {
moe::OptionSection storage_options("Storage options");
- storage_options.addOptionChaining(
- "storage.engine", "storageEngine", moe::String, "what storage engine to use");
+ storage_options
+ .addOptionChaining(
+ "storage.engine", "storageEngine", moe::String, "what storage engine to use")
+ .setDefault(optionenvironment::Value("mobile"));
#ifdef _WIN32
boost::filesystem::path currentPath = boost::filesystem::current_path();
diff --git a/src/mongo/client/embedded/embedded_options_parser_init.cpp b/src/mongo/client/embedded/embedded_options_parser_init.cpp
new file mode 100644
index 00000000000..1416556828a
--- /dev/null
+++ b/src/mongo/client/embedded/embedded_options_parser_init.cpp
@@ -0,0 +1,57 @@
+/**
+ * Copyright (C) 2018 MongoDB 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/>.
+ *
+ * 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.
+ */
+
+#include "mongo/util/options_parser/startup_options.h"
+
+#include <iostream>
+
+#include "mongo/util/exit_code.h"
+#include "mongo/util/options_parser/option_description.h"
+#include "mongo/util/options_parser/option_section.h"
+#include "mongo/util/options_parser/options_parser.h"
+#include "mongo/util/options_parser/startup_option_init.h"
+#include "mongo/util/quick_exit.h"
+
+namespace mongo {
+namespace optionenvironment {
+
+MONGO_STARTUP_OPTIONS_PARSE(StartupOptions)(InitializerContext* context) {
+ // Embedded uses a YAML config passed in argv to reuse the existing interface, extract it from
+ // the first element otherwise use empty string.
+ std::string config = !context->args().empty() ? context->args()[0] : "";
+
+ OptionsParser parser;
+ Status ret =
+ parser.runConfigFile(startupOptions, config, context->env(), &startupOptionsParsed);
+ uassertStatusOKWithContext(ret, "Options parsing failed.");
+
+ return Status::OK();
+}
+
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/client/embedded/embedded_transport_layer_test.cpp b/src/mongo/client/embedded/embedded_transport_layer_test.cpp
index df09479c32c..8b5c262a7f2 100644
--- a/src/mongo/client/embedded/embedded_transport_layer_test.cpp
+++ b/src/mongo/client/embedded/embedded_transport_layer_test.cpp
@@ -30,6 +30,7 @@
#include <mongoc.h>
#include <set>
+#include <yaml-cpp/yaml.h>
#include "mongo/client/embedded/functions_for_test.h"
#include "mongo/client/embedded/libmongodbcapi.h"
@@ -55,13 +56,19 @@ protected:
if (!globalTempDir) {
globalTempDir = mongo::stdx::make_unique<mongo::unittest::TempDir>("embedded_mongo");
}
- int argc = 5;
- const char* argv[] = {"mongo_embedded_transport_layer_test",
- "--storageEngine",
- "mobile",
- "--dbpath",
- globalTempDir->path().c_str()};
- db_handle = libmongodbcapi_db_new(argc, argv, nullptr);
+
+ YAML::Emitter yaml;
+ yaml << YAML::BeginMap;
+
+ yaml << YAML::Key << "storage";
+ yaml << YAML::Value << YAML::BeginMap;
+ yaml << YAML::Key << "dbPath";
+ yaml << YAML::Value << globalTempDir->path();
+ yaml << YAML::EndMap; // storage
+
+ yaml << YAML::EndMap;
+
+ db_handle = libmongodbcapi_db_new(yaml.c_str());
cd_client = embedded_mongoc_client_new(db_handle);
mongoc_client_set_error_api(cd_client, 2);
diff --git a/src/mongo/client/embedded/libmongodbcapi.cpp b/src/mongo/client/embedded/libmongodbcapi.cpp
index 233422cd34b..0b38c244e0a 100644
--- a/src/mongo/client/embedded/libmongodbcapi.cpp
+++ b/src/mongo/client/embedded/libmongodbcapi.cpp
@@ -56,11 +56,6 @@ struct libmongodbcapi_db {
mongo::stdx::unordered_map<libmongodbcapi_client*, std::unique_ptr<libmongodbcapi_client>>
open_clients;
std::unique_ptr<mongo::transport::TransportLayerMock> transportLayer;
-
- std::vector<std::unique_ptr<char[]>> argvStorage;
- std::vector<char*> argvPointers;
- std::vector<std::unique_ptr<char[]>> envpStorage;
- std::vector<char*> envpPointers;
};
struct libmongodbcapi_client {
libmongodbcapi_client(libmongodbcapi_db* db) : parent_db(db) {}
@@ -82,7 +77,7 @@ bool libraryInitialized_ = false;
libmongodbcapi_db* global_db = nullptr;
thread_local int last_error = LIBMONGODB_CAPI_SUCCESS;
-libmongodbcapi_db* db_new(int argc, const char** argv, const char** envp) noexcept try {
+libmongodbcapi_db* db_new(const char* yaml_config) noexcept try {
last_error = LIBMONGODB_CAPI_SUCCESS;
if (!libraryInitialized_)
throw std::runtime_error("libmongodbcapi_init not called");
@@ -91,29 +86,7 @@ libmongodbcapi_db* db_new(int argc, const char** argv, const char** envp) noexce
}
global_db = new libmongodbcapi_db;
- // iterate over argv and copy them to argvStorage
- for (int i = 0; i < argc; i++) {
- // allocate space for the null terminator
- auto s = mongo::stdx::make_unique<char[]>(std::strlen(argv[i]) + 1);
- // copy the string + null terminator
- std::strncpy(s.get(), argv[i], std::strlen(argv[i]) + 1);
- global_db->argvPointers.push_back(s.get());
- global_db->argvStorage.push_back(std::move(s));
- }
- global_db->argvPointers.push_back(nullptr);
-
- // iterate over envp and copy them to envpStorage
- while (envp != nullptr && *envp != nullptr) {
- auto s = mongo::stdx::make_unique<char[]>(std::strlen(*envp) + 1);
- std::strncpy(s.get(), *envp, std::strlen(*envp) + 1);
- global_db->envpPointers.push_back(s.get());
- global_db->envpStorage.push_back(std::move(s));
- envp++;
- }
- global_db->envpPointers.push_back(nullptr);
-
- global_db->serviceContext =
- embedded::initialize(argc, global_db->argvPointers.data(), global_db->envpPointers.data());
+ global_db->serviceContext = embedded::initialize(yaml_config);
if (!global_db->serviceContext) {
delete global_db;
global_db = nullptr;
@@ -225,8 +198,8 @@ int libmongodbcapi_fini() {
return LIBMONGODB_CAPI_SUCCESS;
}
-libmongodbcapi_db* libmongodbcapi_db_new(int argc, const char** argv, const char** envp) {
- return mongo::db_new(argc, argv, envp);
+libmongodbcapi_db* libmongodbcapi_db_new(const char* yaml_config) {
+ return mongo::db_new(yaml_config);
}
int libmongodbcapi_db_destroy(libmongodbcapi_db* db) {
diff --git a/src/mongo/client/embedded/libmongodbcapi.h b/src/mongo/client/embedded/libmongodbcapi.h
index 8c1646dd9b6..f20f6675a5d 100644
--- a/src/mongo/client/embedded/libmongodbcapi.h
+++ b/src/mongo/client/embedded/libmongodbcapi.h
@@ -79,16 +79,12 @@ int libmongodbcapi_fini();
/**
* Starts the database and returns a handle with the service context.
*
-* @param argc
-* The number of arguments in argv
-* @param argv
-* The arguments that will be passed to mongod at startup to initialize state
-* @param envp
-* Environment variables that will be passed to mongod at startup to initilize state
+* @param config null-terminated YAML formatted MongoDB configuration. See documentation for valid
+* options.
*
* @return A pointer to a db handle or null on error
*/
-libmongodbcapi_db* libmongodbcapi_db_new(int argc, const char** argv, const char** envp);
+libmongodbcapi_db* libmongodbcapi_db_new(const char* yaml_config);
/**
* Shuts down the database
diff --git a/src/mongo/client/embedded/libmongodbcapi_test.cpp b/src/mongo/client/embedded/libmongodbcapi_test.cpp
index 8a388b2f757..74c6164d5bf 100644
--- a/src/mongo/client/embedded/libmongodbcapi_test.cpp
+++ b/src/mongo/client/embedded/libmongodbcapi_test.cpp
@@ -30,6 +30,7 @@
#include "mongo/client/embedded/libmongodbcapi.h"
#include <set>
+#include <yaml-cpp/yaml.h>
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/db/json.h"
@@ -68,14 +69,19 @@ protected:
if (!globalTempDir) {
globalTempDir = mongo::stdx::make_unique<mongo::unittest::TempDir>("embedded_mongo");
}
- const char* argv[] = {"mongo_embedded_capi_test",
- "--port",
- "0",
- "--storageEngine",
- "mobile",
- "--dbpath",
- globalTempDir->path().c_str()};
- db = libmongodbcapi_db_new(7, argv, nullptr);
+
+ YAML::Emitter yaml;
+ yaml << YAML::BeginMap;
+
+ yaml << YAML::Key << "storage";
+ yaml << YAML::Value << YAML::BeginMap;
+ yaml << YAML::Key << "dbPath";
+ yaml << YAML::Value << globalTempDir->path();
+ yaml << YAML::EndMap; // storage
+
+ yaml << YAML::EndMap;
+
+ db = libmongodbcapi_db_new(yaml.c_str());
ASSERT(db != nullptr);
}
@@ -428,7 +434,7 @@ TEST_F(MongodbCAPITest, InsertAndUpdate) {
// This test is temporary to make sure that only one database can be created
// This restriction may be relaxed at a later time
TEST_F(MongodbCAPITest, CreateMultipleDBs) {
- libmongodbcapi_db* db2 = libmongodbcapi_db_new(0, nullptr, nullptr);
+ libmongodbcapi_db* db2 = libmongodbcapi_db_new(nullptr);
ASSERT(db2 == nullptr);
ASSERT_EQUALS(libmongodbcapi_get_last_error(), LIBMONGODB_CAPI_ERROR_UNKNOWN);
}
diff --git a/src/mongo/util/options_parser/options_parser.cpp b/src/mongo/util/options_parser/options_parser.cpp
index 2137e7691d1..ec1705c4e03 100644
--- a/src/mongo/util/options_parser/options_parser.cpp
+++ b/src/mongo/util/options_parser/options_parser.cpp
@@ -1141,23 +1141,10 @@ Status OptionsParser::run(const OptionSection& options,
return ret;
}
- YAML::Node YAMLConfig;
- ret = parseYAMLConfigFile(config_file, &YAMLConfig);
+ ret = parseConfigFile(options, config_file, &configEnvironment);
if (!ret.isOK()) {
return ret;
}
-
- if (isYAMLConfig(YAMLConfig)) {
- ret = addYAMLNodesToEnvironment(YAMLConfig, options, "", &configEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
- } else {
- ret = parseINIConfigFile(options, config_file, &configEnvironment);
- if (!ret.isOK()) {
- return ret;
- }
- }
}
// Adds the values for all our options that were registered as composable to the composed
@@ -1211,5 +1198,56 @@ Status OptionsParser::run(const OptionSection& options,
return Status::OK();
}
+Status OptionsParser::runConfigFile(
+ const OptionSection& options,
+ const std::string& config,
+ const std::map<std::string, std::string>& env, // Unused, interface consistent with run()
+ Environment* configEnvironment) {
+ // Add the default values to our resulting environment
+ Status ret = addDefaultValues(options, configEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ // Add values from the provided config file
+ ret = parseConfigFile(options, config, configEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ // Add the constraints from our options to the result environment
+ ret = addConstraints(options, configEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ return ret;
+}
+
+Status OptionsParser::parseConfigFile(const OptionSection& options,
+ const std::string& config_file,
+ Environment* configEnvironment) {
+ YAML::Node YAMLConfig;
+ Status ret = parseYAMLConfigFile(config_file, &YAMLConfig);
+ if (!ret.isOK()) {
+ return ret;
+ }
+
+ // Check if YAML parsing was successful, if not try to read as INI
+ if (isYAMLConfig(YAMLConfig)) {
+ ret = addYAMLNodesToEnvironment(YAMLConfig, options, "", configEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+ } else {
+ ret = parseINIConfigFile(options, config_file, configEnvironment);
+ if (!ret.isOK()) {
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
} // namespace optionenvironment
} // namespace mongo
diff --git a/src/mongo/util/options_parser/options_parser.h b/src/mongo/util/options_parser/options_parser.h
index 26954debb59..a5beab53d97 100644
--- a/src/mongo/util/options_parser/options_parser.h
+++ b/src/mongo/util/options_parser/options_parser.h
@@ -110,6 +110,15 @@ public:
const std::map<std::string, std::string>& env,
Environment*);
+ /** Handles parsing of a YAML or INI formatted string. The
+ * OptionSection be a description of the allowed options. This function populates the
+ * given Environment with the results but does not call validate on the Environment.
+ */
+ Status runConfigFile(const OptionSection&,
+ const std::string& config,
+ const std::map<std::string, std::string>& env,
+ Environment*);
+
private:
/** Handles parsing of the command line and adds the results to the given Environment */
Status parseCommandLine(const OptionSection&,
@@ -120,6 +129,10 @@ private:
* */
Status parseINIConfigFile(const OptionSection&, const std::string& config, Environment*);
+ /** Handles parsing of either YAML or INI config and adds the results to the given Environment
+ */
+ Status parseConfigFile(const OptionSection&, const std::string& argv, Environment*);
+
/** Gets defaults from the OptionSection and adds them to the given Environment */
Status addDefaultValues(const OptionSection&, Environment*);