diff options
author | Andrew Morrow <acm@mongodb.com> | 2016-08-12 15:06:02 -0400 |
---|---|---|
committer | Andrew Morrow <acm@mongodb.com> | 2016-08-15 18:36:28 -0400 |
commit | dacf1667d1e650b4854ad33738b63ff379faec92 (patch) | |
tree | 63e0247eb0291604c4e76f254ce2606edd9925b8 /src/mongo | |
parent | 2114a082f97dbe4263b10b836aca3332af5caca2 (diff) | |
download | mongo-dacf1667d1e650b4854ad33738b63ff379faec92.tar.gz |
SERVER-25402 Fewer binaries depend on interpolated version info
Diffstat (limited to 'src/mongo')
32 files changed, 631 insertions, 272 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript index b88e41b999e..4dd5a21f7f8 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -195,7 +195,7 @@ for tup in env['MONGO_BUILDINFO_ENVIRONMENT_DATA']: buildInfoInitializer = '{{ {0} }}'.format(', '.join(buildInfoInitializer)) generatedVersionFile = env.Substfile( - 'util/version.cpp.in', + 'util/version_constants.h.in', SUBST_DICT=[ ('@mongo_version@', env['MONGO_VERSION']), ('@mongo_version_major@', version_parts[0]), @@ -261,6 +261,7 @@ mongodLibDeps = [ "transport/service_entry_point_utils", "util/clock_sources", "util/ntservice", + "util/version_impl", ] if has_option('use-cpu-profiler'): @@ -321,6 +322,7 @@ env.Install( 'util/clock_sources', 'util/ntservice', 'util/options_parser/options_parser_init', + 'util/version_impl', ])) env.Library("linenoise_utf8", @@ -378,6 +380,7 @@ if not has_option('noshell') and usemozjs: 'util/options_parser/options_parser_init', 'util/processinfo', 'util/signal_handlers', + 'util/version_impl', 'executor/thread_pool_task_executor', 'executor/network_interface_thread_pool', 'executor/network_interface_factory' diff --git a/src/mongo/base/string_data.h b/src/mongo/base/string_data.h index d9394c41711..029da4a2cee 100644 --- a/src/mongo/base/string_data.h +++ b/src/mongo/base/string_data.h @@ -333,4 +333,16 @@ inline bool StringData::endsWith(StringData suffix) const { return substr(thisSize - suffixSize) == suffix; } +inline std::string operator+(std::string lhs, StringData rhs) { + if (!rhs.empty()) + lhs.append(rhs.rawData(), rhs.size()); + return lhs; +} + +inline std::string operator+(StringData lhs, std::string rhs) { + if (!lhs.empty()) + rhs.insert(0, lhs.rawData(), lhs.size()); + return rhs; +} + } // namespace mongo diff --git a/src/mongo/client/SConscript b/src/mongo/client/SConscript index d1e37207f5e..aad23a013fb 100644 --- a/src/mongo/client/SConscript +++ b/src/mongo/client/SConscript @@ -243,6 +243,7 @@ env.CppUnitTest( '$BUILD_DIR/mongo/db/service_context_noop_init', '$BUILD_DIR/mongo/transport/transport_layer_legacy', '$BUILD_DIR/mongo/util/net/network', + '$BUILD_DIR/mongo/util/version_impl', ], ) diff --git a/src/mongo/client/dbclient.cpp b/src/mongo/client/dbclient.cpp index 989deeffc7f..51f5fe04c94 100644 --- a/src/mongo/client/dbclient.cpp +++ b/src/mongo/client/dbclient.cpp @@ -725,8 +725,10 @@ executor::RemoteCommandResponse initWireVersion(DBClientConnection* conn, bob.append("hostInfo", sb.str()); } + auto versionString = VersionInfoInterface::instance().version(); + Status serializeStatus = ClientMetadata::serialize( - "MongoDB Internal Client", mongo::versionString, applicationName, &bob); + "MongoDB Internal Client", versionString, applicationName, &bob); if (!serializeStatus.isOK()) { return serializeStatus; } diff --git a/src/mongo/db/commands/generic.cpp b/src/mongo/db/commands/generic.cpp index 941ac0d2503..9ef0f60adf1 100644 --- a/src/mongo/db/commands/generic.cpp +++ b/src/mongo/db/commands/generic.cpp @@ -95,7 +95,7 @@ public: int, // options std::string& errmsg, BSONObjBuilder& result) { - appendBuildInfo(result); + VersionInfoInterface::instance().appendBuildInfo(&result); appendStorageEngineList(&result); return true; } diff --git a/src/mongo/db/commands/server_status.cpp b/src/mongo/db/commands/server_status.cpp index 531d477db5f..ff0b1cbb376 100644 --- a/src/mongo/db/commands/server_status.cpp +++ b/src/mongo/db/commands/server_status.cpp @@ -106,7 +106,7 @@ public: result.append("host", prettyHostName()); result.append("advisoryHostFQDNs", canonicalizer->getCanonicalizedFQDNs()); - result.append("version", versionString); + result.append("version", VersionInfoInterface::instance().version()); result.append("process", serverGlobalParams.binaryName); result.append("pid", ProcessId::getCurrent().asLongLong()); result.append("uptime", (double)(time(0) - serverGlobalParams.started)); diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp index 270e8e7ea41..c10f85b94c4 100644 --- a/src/mongo/db/db.cpp +++ b/src/mongo/db/db.cpp @@ -188,7 +188,7 @@ static void logStartup(OperationContext* txn) { BSONObjBuilder buildinfo(toLog.subobjStart("buildinfo")); - appendBuildInfo(buildinfo); + VersionInfoInterface::instance().appendBuildInfo(&buildinfo); appendStorageEngineList(&buildinfo); buildinfo.doneFast(); @@ -509,7 +509,7 @@ static ExitCode _initAndListen(int listenPort) { DEV log(LogComponent::kControl) << "DEBUG build (which is slower)" << endl; #if defined(_WIN32) - printTargetMinOS(); + VersionInfoInterface::instance().logTargetMinOS(); #endif logProcessDetails(); diff --git a/src/mongo/db/dbwebserver.cpp b/src/mongo/db/dbwebserver.cpp index a5b9ca74fdb..b202e0500b9 100644 --- a/src/mongo/db/dbwebserver.cpp +++ b/src/mongo/db/dbwebserver.cpp @@ -74,10 +74,11 @@ namespace { void doUnlockedStuff(stringstream& ss) { // This is in the header already ss << "port: " << port << '\n' + auto&& vii = VersionInfoInterface::instance(); ss << "<pre>"; - ss << mongodVersion() << '\n'; - ss << "git hash: " << gitVersion() << '\n'; - ss << openSSLVersion("OpenSSL version: ", "\n"); + ss << mongodVersion(vii) << '\n'; + ss << "git hash: " << vii.gitVersion() << '\n'; + ss << vii.openSSLVersion("OpenSSL version: ", "\n"); ss << "uptime: " << time(0) - serverGlobalParams.started << " seconds\n"; ss << "</pre>"; } diff --git a/src/mongo/db/log_process_details.cpp b/src/mongo/db/log_process_details.cpp index cd75444fe69..125106fd331 100644 --- a/src/mongo/db/log_process_details.cpp +++ b/src/mongo/db/log_process_details.cpp @@ -48,8 +48,9 @@ bool is32bit() { } void logProcessDetails() { - log() << mongodVersion(); - printBuildInfo(); + auto&& vii = VersionInfoInterface::instance(); + log() << mongodVersion(vii); + vii.logBuildInfo(); printCommandLineOpts(); } diff --git a/src/mongo/db/mongod_options.cpp b/src/mongo/db/mongod_options.cpp index 161475d567b..b030a26d3a9 100644 --- a/src/mongo/db/mongod_options.cpp +++ b/src/mongo/db/mongod_options.cpp @@ -599,8 +599,9 @@ bool handlePreValidationMongodOptions(const moe::Environment& params, } if (params.count("version") && params["version"].as<bool>() == true) { setPlainConsoleLogger(); - log() << mongodVersion() << endl; - printBuildInfo(); + auto&& vii = VersionInfoInterface::instance(); + log() << mongodVersion(vii); + vii.logBuildInfo(); return false; } if (params.count("sysinfo") && params["sysinfo"].as<bool>() == true) { diff --git a/src/mongo/db/query/explain.cpp b/src/mongo/db/query/explain.cpp index af29fa60d08..944c730ebf4 100644 --- a/src/mongo/db/query/explain.cpp +++ b/src/mongo/db/query/explain.cpp @@ -676,8 +676,9 @@ void Explain::generateServerInfo(BSONObjBuilder* out) { BSONObjBuilder serverBob(out->subobjStart("serverInfo")); out->append("host", getHostNameCached()); out->appendNumber("port", serverGlobalParams.port); - out->append("version", versionString); - out->append("gitVersion", gitVersion()); + auto&& vii = VersionInfoInterface::instance(); + out->append("version", vii.version()); + out->append("gitVersion", vii.gitVersion()); serverBob.doneFast(); } diff --git a/src/mongo/db/startup_warnings_common.cpp b/src/mongo/db/startup_warnings_common.cpp index c045a3f5f8d..9c444410b51 100644 --- a/src/mongo/db/startup_warnings_common.cpp +++ b/src/mongo/db/startup_warnings_common.cpp @@ -51,11 +51,10 @@ void logCommonStartupWarnings(const ServerGlobalParams& serverParams) { bool warned = false; { - const char* foo = strchr(versionString, '.') + 1; - int bar = atoi(foo); - if ((2 * (bar / 2)) != bar) { + auto&& vii = VersionInfoInterface::instance(); + if ((vii.minorVersion() % 2) != 0) { log() << startupWarningsLog; - log() << "** NOTE: This is a development version (" << versionString << ") of MongoDB." + log() << "** NOTE: This is a development version (" << vii.version() << ") of MongoDB." << startupWarningsLog; log() << "** Not recommended for production." << startupWarningsLog; warned = true; diff --git a/src/mongo/dbtests/SConscript b/src/mongo/dbtests/SConscript index 54134152792..8bfb544fb84 100644 --- a/src/mongo/dbtests/SConscript +++ b/src/mongo/dbtests/SConscript @@ -125,6 +125,7 @@ dbtest = env.Program( '$BUILD_DIR/mongo/util/clock_source_mock', "$BUILD_DIR/mongo/util/concurrency/rwlock", "$BUILD_DIR/mongo/util/net/network", + "$BUILD_DIR/mongo/util/version_impl", "mocklib", "testframework", ], diff --git a/src/mongo/dbtests/framework.cpp b/src/mongo/dbtests/framework.cpp index 516559004fa..53826e931a0 100644 --- a/src/mongo/dbtests/framework.cpp +++ b/src/mongo/dbtests/framework.cpp @@ -86,7 +86,6 @@ int runDbTests(int argc, char** argv) { }); srand((unsigned)frameworkGlobalParams.seed); - printBuildInfo(); checked_cast<ServiceContextMongoD*>(globalServiceContext)->createLockFile(); globalServiceContext->initializeGlobalStorageEngine(); diff --git a/src/mongo/dbtests/perftests.cpp b/src/mongo/dbtests/perftests.cpp index 0eb5b3c0925..6c4ac4751e3 100644 --- a/src/mongo/dbtests/perftests.cpp +++ b/src/mongo/dbtests/perftests.cpp @@ -226,17 +226,18 @@ public: } { + auto&& vii = VersionInfoInterface::instance(); bob inf; - inf.append("version", versionString); + inf.append("version", vii.version()); if (sizeof(int*) == 4) inf.append("bits", 32); DEV inf.append("DEBUG", true); #if defined(_WIN32) inf.append("os", "win"); #endif - inf.append("git", gitVersion()); + inf.append("git", vii.gitVersion()); #ifdef MONGO_CONFIG_SSL - inf.append("OpenSSL", openSSLVersion()); + inf.append("OpenSSL", vii.openSSLVersion()); #endif inf.append("boost", BOOST_VERSION); b.append("info", inf.obj()); diff --git a/src/mongo/executor/SConscript b/src/mongo/executor/SConscript index 6f38a8c3442..951f4663679 100644 --- a/src/mongo/executor/SConscript +++ b/src/mongo/executor/SConscript @@ -107,6 +107,7 @@ env.CppIntegrationTest( '$BUILD_DIR/mongo/executor/thread_pool_task_executor', '$BUILD_DIR/mongo/executor/network_interface_thread_pool', '$BUILD_DIR/mongo/executor/network_interface_factory', + '$BUILD_DIR/mongo/util/version_impl', ], ) @@ -192,7 +193,8 @@ env.CppUnitTest( 'network_interface_asio', '$BUILD_DIR/mongo/executor/thread_pool_task_executor', '$BUILD_DIR/mongo/executor/network_interface_thread_pool', - '$BUILD_DIR/mongo/executor/network_interface_factory' + '$BUILD_DIR/mongo/executor/network_interface_factory', + '$BUILD_DIR/mongo/util/version_impl', ], ) @@ -207,6 +209,7 @@ env.CppIntegrationTest( '$BUILD_DIR/mongo/executor/network_interface_factory', '$BUILD_DIR/mongo/rpc/command_status', '$BUILD_DIR/mongo/util/concurrency/thread_pool', + '$BUILD_DIR/mongo/util/version_impl', 'network_interface_asio', ], ) @@ -224,6 +227,7 @@ env.CppIntegrationTest( '$BUILD_DIR/mongo/db/auth/authorization_manager_mock_init', '$BUILD_DIR/mongo/db/service_context_noop_init', '$BUILD_DIR/mongo/rpc/command_status', + '$BUILD_DIR/mongo/util/version_impl', ], ) diff --git a/src/mongo/executor/network_interface_asio_auth.cpp b/src/mongo/executor/network_interface_asio_auth.cpp index 69fb2c0bc10..d2e341007e6 100644 --- a/src/mongo/executor/network_interface_asio_auth.cpp +++ b/src/mongo/executor/network_interface_asio_auth.cpp @@ -64,7 +64,9 @@ void NetworkInterfaceASIO::_runIsMaster(AsyncOp* op) { BSONObjBuilder bob; bob.append("isMaster", 1); bob.append("hangUpOnStepDown", false); - ClientMetadata::serialize(_options.instanceName, mongo::versionString, &bob); + + const auto versionString = VersionInfoInterface::instance().version(); + ClientMetadata::serialize(_options.instanceName, versionString, &bob); if (Command::testCommandsEnabled) { // Only include the host:port of this process in the isMaster command request if test diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index 9a576511991..a4147f3bc16 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -350,6 +350,7 @@ env.CppUnitTest( ], LIBDEPS=[ '$BUILD_DIR/mongo/db/repl/replmocks', + '$BUILD_DIR/mongo/util/version_impl', 'config_server_test_fixture', 'coreshard', ] diff --git a/src/mongo/s/balancer/balancer.cpp b/src/mongo/s/balancer/balancer.cpp index b21213d7f0c..0f113755e0b 100644 --- a/src/mongo/s/balancer/balancer.cpp +++ b/src/mongo/s/balancer/balancer.cpp @@ -117,9 +117,12 @@ private: * in the cluster. */ void warnOnMultiVersion(const vector<ClusterStatistics::ShardStatistics>& clusterStats) { + + auto&& vii = VersionInfoInterface::instance(); + bool isMultiVersion = false; for (const auto& stat : clusterStats) { - if (!isSameMajorVersion(stat.mongoVersion.c_str())) { + if (!vii.isSameMajorVersion(stat.mongoVersion.c_str())) { isMultiVersion = true; break; } @@ -130,7 +133,7 @@ void warnOnMultiVersion(const vector<ClusterStatistics::ShardStatistics>& cluste return; StringBuilder sb; - sb << "Multi version cluster detected. Local version: " << versionString + sb << "Multi version cluster detected. Local version: " << vii.version() << ", shard versions: "; for (const auto& stat : clusterStats) { diff --git a/src/mongo/s/sharding_uptime_reporter.cpp b/src/mongo/s/sharding_uptime_reporter.cpp index 8ec02ea20a9..8a4b8d756d1 100644 --- a/src/mongo/s/sharding_uptime_reporter.cpp +++ b/src/mongo/s/sharding_uptime_reporter.cpp @@ -84,7 +84,7 @@ void ShardingUptimeReporter::reportStatus(OperationContext* txn, bool isBalancer mType.setPing(jsTime()); mType.setUptime(_timer.seconds()); mType.setWaiting(!isBalancerActive); - mType.setMongoVersion(versionString); + mType.setMongoVersion(VersionInfoInterface::instance().version().toString()); try { Grid::get(txn)->catalogClient(txn)->updateConfigDocument( diff --git a/src/mongo/s/version_mongos.cpp b/src/mongo/s/version_mongos.cpp index efa5e78a9bc..47b5373bebd 100644 --- a/src/mongo/s/version_mongos.cpp +++ b/src/mongo/s/version_mongos.cpp @@ -42,13 +42,14 @@ namespace mongo { void printShardingVersionInfo(bool out) { + auto&& vii = VersionInfoInterface::instance(); if (out) { setPlainConsoleLogger(); - log() << mongosVersion(); - printBuildInfo(); + log() << mongosVersion(vii); + vii.logBuildInfo(); } else { - log() << mongosVersion(); - printBuildInfo(); + log() << mongosVersion(vii); + vii.logBuildInfo(); logProcessDetails(); } } diff --git a/src/mongo/scripting/mozjs/global.cpp b/src/mongo/scripting/mozjs/global.cpp index 3266eb21797..105d9478dba 100644 --- a/src/mongo/scripting/mozjs/global.cpp +++ b/src/mongo/scripting/mozjs/global.cpp @@ -86,12 +86,13 @@ void GlobalInfo::Functions::print::call(JSContext* cx, JS::CallArgs args) { } void GlobalInfo::Functions::version::call(JSContext* cx, JS::CallArgs args) { + auto versionString = VersionInfoInterface::instance().version(); ValueReader(cx, args.rval()).fromStringData(versionString); } void GlobalInfo::Functions::buildInfo::call(JSContext* cx, JS::CallArgs args) { BSONObjBuilder b; - appendBuildInfo(b); + VersionInfoInterface::instance().appendBuildInfo(&b); ValueReader(cx, args.rval()).fromBSON(b.obj(), nullptr, false); } diff --git a/src/mongo/shell/dbshell.cpp b/src/mongo/shell/dbshell.cpp index 66b03166ce6..97f80abeb5e 100644 --- a/src/mongo/shell/dbshell.cpp +++ b/src/mongo/shell/dbshell.cpp @@ -600,7 +600,7 @@ int _main(int argc, char* argv[], char** envp) { } if (!mongo::serverGlobalParams.quiet) - cout << mongoShellVersion() << endl; + cout << mongoShellVersion(VersionInfoInterface::instance()) << endl; mongo::StartupTest::runTests(); diff --git a/src/mongo/shell/shell_options.cpp b/src/mongo/shell/shell_options.cpp index 49037e6e12d..1b378836c35 100644 --- a/src/mongo/shell/shell_options.cpp +++ b/src/mongo/shell/shell_options.cpp @@ -218,13 +218,14 @@ std::string getMongoShellHelp(StringData name, const moe::OptionSection& options bool handlePreValidationMongoShellOptions(const moe::Environment& params, const std::vector<std::string>& args) { + auto&& vii = VersionInfoInterface::instance(); if (params.count("version") || params.count("help")) { setPlainConsoleLogger(); - log() << mongoShellVersion(); + log() << mongoShellVersion(vii); if (params.count("help")) { log() << getMongoShellHelp(args[0], moe::startupOptions); } else { - printBuildInfo(); + vii.logBuildInfo(); } return false; } diff --git a/src/mongo/shell/shell_utils.cpp b/src/mongo/shell/shell_utils.cpp index e4edd8d9391..1e79ab36f0a 100644 --- a/src/mongo/shell/shell_utils.cpp +++ b/src/mongo/shell/shell_utils.cpp @@ -174,7 +174,7 @@ BSONObj isAddressSanitizerActive(const BSONObj& a, void* data) { BSONObj getBuildInfo(const BSONObj& a, void* data) { uassert(16822, "getBuildInfo accepts no arguments", a.nFields() == 0); BSONObjBuilder b; - appendBuildInfo(b); + VersionInfoInterface::instance().appendBuildInfo(&b); return BSON("" << b.done()); } diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript index 7b09db3b5ba..1898f8aa3c9 100644 --- a/src/mongo/util/SConscript +++ b/src/mongo/util/SConscript @@ -15,6 +15,16 @@ env.SConscript( ) env.Library( + target='version_impl', + source=[ + 'version_impl.cpp', + ], + LIBDEPS=[ + '$BUILD_DIR/mongo/base', + ] +) + +env.Library( target='intrusive_counter', source=[ 'intrusive_counter.cpp', diff --git a/src/mongo/util/stacktrace_posix.cpp b/src/mongo/util/stacktrace_posix.cpp index 7915eafdd3a..4443e755e19 100644 --- a/src/mongo/util/stacktrace_posix.cpp +++ b/src/mongo/util/stacktrace_posix.cpp @@ -255,9 +255,12 @@ void addOSComponentsToSoMap(BSONObjBuilder* soMap); */ MONGO_INITIALIZER(ExtractSOMap)(InitializerContext*) { BSONObjBuilder soMap; - soMap << "mongodbVersion" << versionString; - soMap << "gitVersion" << gitVersion(); - soMap << "compiledModules" << compiledModules(); + + auto&& vii = VersionInfoInterface::instance(VersionInfoInterface::NotEnabledAction::kFallback); + soMap << "mongodbVersion" << vii.version(); + soMap << "gitVersion" << vii.gitVersion(); + soMap << "compiledModules" << vii.modules(); + struct utsname unameData; if (!uname(&unameData)) { BSONObjBuilder unameBuilder(soMap.subobjStart("uname")); diff --git a/src/mongo/util/version.cpp b/src/mongo/util/version.cpp new file mode 100644 index 00000000000..41933e8c9ac --- /dev/null +++ b/src/mongo/util/version.cpp @@ -0,0 +1,232 @@ +/* Copyright 2016 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/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kControl + +#include "mongo/platform/basic.h" + +#include "mongo/util/version.h" + +#include "mongo/config.h" + +#ifdef MONGO_CONFIG_SSL +#include <openssl/crypto.h> +#endif + +#include <pcrecpp.h> + +#include <sstream> + +#include "mongo/db/jsobj.h" +#include "mongo/util/assert_util.h" +#include "mongo/util/log.h" + +namespace mongo { +namespace { + +const class : public VersionInfoInterface { +public: + int majorVersion() const noexcept final { + return 0; + } + + int minorVersion() const noexcept final { + return 0; + } + + int patchVersion() const noexcept final { + return 0; + } + + int extraVersion() const noexcept final { + return 0; + } + + StringData version() const noexcept final { + return "unknown"; + } + + StringData gitVersion() const noexcept final { + return "none"; + } + + std::vector<StringData> modules() const final { + return {"unknown"}; + } + + StringData allocator() const noexcept final { + return "unknown"; + } + + StringData jsEngine() const noexcept final { + return "unknown"; + } + + StringData targetMinOS() const noexcept final { + return "unknown"; + } + + std::vector<BuildInfoTuple> buildInfo() const final { + return {}; + } + +} kFallbackVersionInfo{}; + +const VersionInfoInterface* globalVersionInfo = nullptr; + +} // namespace + +void VersionInfoInterface::enable(const VersionInfoInterface* handler) { + globalVersionInfo = handler; +} + +const VersionInfoInterface& VersionInfoInterface::instance(NotEnabledAction action) noexcept { + if (globalVersionInfo) + return *globalVersionInfo; + if (action == NotEnabledAction::kFallback) + return kFallbackVersionInfo; + severe() << "Terminating because valid version info has not been configured"; + fassertFailed(40278); +} + +bool VersionInfoInterface::isSameMajorVersion(const char* otherVersion) const noexcept { + int major = -1, minor = -1; + pcrecpp::RE ver_regex("^(\\d+)\\.(\\d+)\\."); + ver_regex.PartialMatch(otherVersion, &major, &minor); + + if (major == -1 || minor == -1) + return false; + + return (major == majorVersion() && minor == minorVersion()); +} + +std::string VersionInfoInterface::makeVersionString(StringData binaryName) const { + std::stringstream ss; + ss << binaryName << " v" << version(); + return ss.str(); +} + +void VersionInfoInterface::appendBuildInfo(BSONObjBuilder* result) const { + *result << "version" << version() << "gitVersion" << gitVersion() +#if defined(_WIN32) + << "targetMinOS" << targetMinOS() +#endif + << "modules" << modules() << "allocator" << allocator() << "javascriptEngine" + << jsEngine() << "sysInfo" + << "deprecated"; + + BSONArrayBuilder versionArray(result->subarrayStart("versionArray")); + versionArray << majorVersion() << minorVersion() << patchVersion() << extraVersion(); + versionArray.done(); + + BSONObjBuilder opensslInfo(result->subobjStart("openssl")); +#ifdef MONGO_CONFIG_SSL + opensslInfo << "running" << openSSLVersion() << "compiled" << OPENSSL_VERSION_TEXT; +#else + opensslInfo << "running" + << "disabled" + << "compiled" + << "disabled"; +#endif + opensslInfo.done(); + + BSONObjBuilder buildvarsInfo(result->subobjStart("buildEnvironment")); + for (auto&& envDataEntry : buildInfo()) { + if (std::get<2>(envDataEntry)) { + buildvarsInfo << std::get<0>(envDataEntry) << std::get<1>(envDataEntry); + } + } + buildvarsInfo.done(); + + *result << "bits" << (int)sizeof(void*) * 8; + result->appendBool("debug", kDebugBuild); + result->appendNumber("maxBsonObjectSize", BSONObjMaxUserSize); +} + +std::string VersionInfoInterface::openSSLVersion(StringData prefix, StringData suffix) const { +#ifndef MONGO_CONFIG_SSL + return ""; +#else + return prefix.toString() + SSLeay_version(SSLEAY_VERSION) + suffix; +#endif +} + +void VersionInfoInterface::logTargetMinOS() const { + log() << "targetMinOS: " << targetMinOS(); +} + +void VersionInfoInterface::logBuildInfo() const { + log() << "git version: " << gitVersion(); + +#ifdef MONGO_CONFIG_SSL + log() << openSSLVersion("OpenSSL version: "); +#endif + + log() << "allocator: " << allocator(); + + std::stringstream ss; + ss << "modules: "; + auto modules_list = modules(); + if (modules_list.size() == 0) { + ss << "none"; + } else { + for (const auto& m : modules_list) { + ss << m << " "; + } + } + log() << ss.str(); + + log() << "build environment:"; + for (auto&& envDataEntry : buildInfo()) { + if (std::get<3>(envDataEntry)) { + auto val = std::get<1>(envDataEntry); + if (val.size() == 0) + continue; + log() << " " << std::get<0>(envDataEntry) << ": " << std::get<1>(envDataEntry); + } + } +} + +std::string mongoShellVersion(const VersionInfoInterface& provider) { + std::stringstream ss; + ss << "MongoDB shell version v" << provider.version(); + return ss.str(); +} + +std::string mongosVersion(const VersionInfoInterface& provider) { + std::stringstream ss; + ss << "mongos version v" << provider.version(); + return ss.str(); +} + +std::string mongodVersion(const VersionInfoInterface& provider) { + std::stringstream ss; + ss << "db version v" << provider.version(); + return ss.str(); +} + +} // namespace mongo diff --git a/src/mongo/util/version.cpp.in b/src/mongo/util/version.cpp.in deleted file mode 100644 index 84550e0f2ef..00000000000 --- a/src/mongo/util/version.cpp.in +++ /dev/null @@ -1,206 +0,0 @@ -// @file version.cpp - -/* Copyright 2009 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/>. - * - * As a special exception, the copyright holders give permission to link the - * code of portions of this program with the OpenSSL library under certain - * conditions as described in each individual source file and distribute - * linked combinations including the program with the OpenSSL library. You - * must comply with the GNU Affero General Public License in all respects - * for all of the code used other than as permitted herein. If you modify - * file(s) with this exception, you may extend this exception to your - * version of the file(s), but you are not obligated to do so. If you do not - * wish to do so, delete this exception statement from your version. If you - * delete this exception statement from all source files in the program, - * then also delete it in the license file. - */ - -#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kControl - -#include "mongo/platform/basic.h" - -#include <initializer_list> -#include <boost/version.hpp> -#include <sstream> -#include <string> - -#include "mongo/base/parse_number.h" -#include "mongo/bson/bsonobjbuilder.h" -#include "mongo/config.h" -#include "mongo/db/jsobj.h" -#include "mongo/util/debug_util.h" -#include "mongo/util/log.h" -#include "mongo/util/mongoutils/str.h" -#include "mongo/util/version.h" - -#ifdef MONGO_CONFIG_SSL -#include <openssl/crypto.h> -#endif - -#include <pcrecpp.h> -#include <cstdlib> - -namespace mongo { - -using std::string; -using std::stringstream; - -const char versionString[] = "@mongo_version@"; -const char* gitVersion() { - return "@mongo_git_hash@"; -} -const char* compiledJSEngine() { - return "@buildinfo_js_engine@"; -} -const char* allocator() { - return "@buildinfo_allocator@"; -} - -const int kMongoVersionMajor = @mongo_version_major@; -const int kMongoVersionMinor = @mongo_version_minor@; -const int kMongoVersionPatch = @mongo_version_patch@; -const int kMongoVersionExtra = @mongo_version_extra@; -const char kMongoVersionExtraStr[] = "@mongo_version_extra_str@"; - -using BuildInfoTuple = std::tuple<std::string, std::string, bool, bool>; -const std::vector<BuildInfoTuple> kBuildEnvironment = @buildinfo_environment_data@; - -std::vector<std::string> compiledModules() { - const std::vector<string> modules_list = @buildinfo_modules@; - return modules_list; -} - -bool isSameMajorVersion(const char* version) { - int major = -1, minor = -1; - pcrecpp::RE ver_regex("^(\\d+)\\.(\\d+)\\."); - ver_regex.PartialMatch(version, &major, &minor); - - if (major == -1 || minor == -1) - return false; - return (major == kMongoVersionMajor && minor == kMongoVersionMinor); -} - -string mongodVersion() { - stringstream ss; - ss << "db version v" << versionString; - return ss.str(); -} - -string mongosVersion() { - stringstream ss; - ss << "mongos version v" << versionString; - return ss.str(); -} - -string mongoShellVersion() { - stringstream ss; - ss << "MongoDB shell version v" << versionString; - return ss.str(); -} - -const std::string openSSLVersion(const std::string& prefix, const std::string& suffix) { -#ifndef MONGO_CONFIG_SSL - return ""; -#else - return prefix + SSLeay_version(SSLEAY_VERSION) + suffix; -#endif -} - -#if defined(_WIN32) -const char* targetMinOS() { -#if (NTDDI_VERSION >= NTDDI_WIN7) - return "Windows 7/Windows Server 2008 R2"; -#elif(NTDDI_VERSION >= NTDDI_VISTA) - return "Windows Vista/Windows Server 2008"; -#else -#error This targeted Windows version is not supported -#endif // NTDDI_VERSION -} - -void printTargetMinOS() { - log() << "targetMinOS: " << targetMinOS(); -} -#endif // _WIN32 - -void printBuildInfo() { - log() << "git version: " << gitVersion(); - -#ifdef MONGO_CONFIG_SSL - log() << openSSLVersion("OpenSSL version: "); -#endif - - log() << "allocator: " << allocator(); - - stringstream ss; - ss << "modules: "; - auto modules_list = compiledModules(); - if (modules_list.size() == 0) { - ss << "none"; - } else { - for (const auto& m : modules_list) { - ss << m << " "; - } - } - log() << ss.str(); - - log() << "build environment:"; - for (auto&& envDataEntry : kBuildEnvironment) { - if (std::get<3>(envDataEntry)) { - auto val = std::get<1>(envDataEntry); - if (val.length() == 0) - continue; - log() << " " << std::get<0>(envDataEntry) << ": " << std::get<1>(envDataEntry); - } - } -} - -void appendBuildInfo(BSONObjBuilder& result) { - result << "version" << versionString << "gitVersion" << gitVersion() -#if defined(_WIN32) - << "targetMinOS" << targetMinOS() -#endif - << "modules" << compiledModules() - << "allocator" << allocator() << "javascriptEngine" << compiledJSEngine() << "sysInfo" - << "deprecated"; - - BSONArrayBuilder versionArray(result.subarrayStart("versionArray")); - versionArray << kMongoVersionMajor << kMongoVersionMinor << kMongoVersionPatch - << kMongoVersionExtra; - versionArray.done(); - - BSONObjBuilder opensslInfo(result.subobjStart("openssl")); -#ifdef MONGO_CONFIG_SSL - opensslInfo << "running" << openSSLVersion() << "compiled" << OPENSSL_VERSION_TEXT; -#else - opensslInfo << "running" - << "disabled" - << "compiled" - << "disabled"; -#endif - opensslInfo.done(); - - BSONObjBuilder buildvarsInfo(result.subobjStart("buildEnvironment")); - for (auto&& envDataEntry : kBuildEnvironment) { - if (std::get<2>(envDataEntry)) { - buildvarsInfo << std::get<0>(envDataEntry) << std::get<1>(envDataEntry); - } - } - buildvarsInfo.done(); - - result << "bits" << (int)sizeof(void*) * 8; - result.appendBool("debug", kDebugBuild); - result.appendNumber("maxBsonObjectSize", BSONObjMaxUserSize); -} -} diff --git a/src/mongo/util/version.h b/src/mongo/util/version.h index f346af8bf6f..3dcddb08b34 100644 --- a/src/mongo/util/version.h +++ b/src/mongo/util/version.h @@ -30,43 +30,154 @@ #define UTIL_VERSION_HEADER #include <string> +#include <tuple> +#include <vector> -#include "mongo/bson/bsonobj.h" +#include "mongo/base/disallow_copying.h" +#include "mongo/base/string_data.h" namespace mongo { -struct BSONArray; + class BSONObjBuilder; -// mongo version -extern const char versionString[]; -extern const int versionNumber; -std::string mongodVersion(); -std::string mongosVersion(); -std::string mongoShellVersion(); +/** + * An interface for accessing version information about the current process. A singleton instance of + * this interface is expected to be available via the 'instance' method in processes that need to be + * able to access version information. + */ +class VersionInfoInterface { + MONGO_DISALLOW_COPYING(VersionInfoInterface); + +public: + using BuildInfoTuple = std::tuple<StringData, StringData, bool, bool>; + + virtual ~VersionInfoInterface() = default; + + /** + * The provided implementation of this interface will be returned by the 'instance' method + * below. Ownership of the object is not transferred. + */ + static void enable(const VersionInfoInterface* handler); + + enum class NotEnabledAction { + kAbortProcess, + kFallback, + }; + + /** + * Obtain the currently configured instance of the VersionInfoInterface. By default, if this + * method is called and no implementation has been configured with the 'enable' method above, + * the process will be terminated. If it is not acceptable to terminate the process, the above + * 'kFallback' constant can be provided and defaulted information will be provided. + */ + static const VersionInfoInterface& instance( + NotEnabledAction action = NotEnabledAction::kAbortProcess) noexcept; + + /** + * Returns the major version as configured via MONGO_VERSION. + */ + virtual int majorVersion() const noexcept = 0; + + /** + * Returns the minor version as configured via MONGO_VERSION. + */ + virtual int minorVersion() const noexcept = 0; + + /** + * Returns the patch version as configured via MONGO_VERSION. + */ + virtual int patchVersion() const noexcept = 0; + + /** + * Returns the extra version as configured via MONGO_VERSION. + */ + virtual int extraVersion() const noexcept = 0; + + /** + * Returns a string representation of MONGO_VERSION. + */ + virtual StringData version() const noexcept = 0; + + /** + * Returns a string representation of MONGO_GIT_HASH. + */ + virtual StringData gitVersion() const noexcept = 0; -// mongo git version -const char* gitVersion(); -const char* distName(); -std::vector<std::string> compiledModules(); + /** + * Returns a vector describing the enabled modules. + */ + virtual std::vector<StringData> modules() const = 0; -// Checks whether another version is the same major version as us -bool isSameMajorVersion(const char* version); + /** + * Returns a string describing the configured memory allocator. + */ + virtual StringData allocator() const noexcept = 0; -// Get/print the version of OpenSSL that's used at runtime -const std::string openSSLVersion(const std::string& prefix = "", const std::string& suffix = ""); + /** + * Returns a string describing the configured javascript engine. + */ + virtual StringData jsEngine() const noexcept = 0; -// Append build info data to a BSONObjBuilder -void appendBuildInfo(BSONObjBuilder& result); + /** + * Returns a string describing the minimum requred OS. Note that this method is currently only + * valid to call when running on Windows. + */ + virtual StringData targetMinOS() const noexcept = 0; -void printTargetMinOS(); -void printBuildInfo(); -void show_warnings(); + /** + * Returns a vector of tuples describing build information (e.g. LINKFLAGS, compiler, etc.). + */ + virtual std::vector<BuildInfoTuple> buildInfo() const = 0; -extern const int kMongoVersionMajor; -extern const int kMongoVersionMinor; -extern const int kMongoVersionPatch; -extern const int kMongoVersionExtra; -extern const char kMongoVersionExtraStr[]; + /** + * Returns the version of OpenSSL in use, if any, adorned with the provided prefix and suffix. + */ + std::string openSSLVersion(StringData prefix = "", StringData suffix = "") const; + + /** + * Returns true if the running version has the same major and minor version as the provided + * string. Note that the minor version is checked, despite the name of this function. + */ + bool isSameMajorVersion(const char* otherVersion) const noexcept; + + /** + * Uses the provided text to make a pretty representation of the version. + */ + std::string makeVersionString(StringData binaryName) const; + + /** + * Appends the information associated with 'buildInfo', above, to the given builder. + */ + void appendBuildInfo(BSONObjBuilder* result) const; + + /** + * Logs the result of 'targetMinOS', above. + */ + void logTargetMinOS() const; + + /** + * Logs the result of 'buildInfo', above. + */ + void logBuildInfo() const; + +protected: + constexpr VersionInfoInterface() = default; +}; + +/** + * Returns a pretty string describing the current shell version. + */ +std::string mongoShellVersion(const VersionInfoInterface& provider); + +/** + * Returns a pretty string describing the current mongos version. + */ +std::string mongosVersion(const VersionInfoInterface& provider); + +/** + * Returns a pretty string describing the current mongod version. + */ +std::string mongodVersion(const VersionInfoInterface& provider); } // namespace mongo diff --git a/src/mongo/util/version_constants.h.in b/src/mongo/util/version_constants.h.in new file mode 100644 index 00000000000..52a4e3d1e04 --- /dev/null +++ b/src/mongo/util/version_constants.h.in @@ -0,0 +1,62 @@ +/* Copyright 2016 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/>. + * + * 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 <initializer_list> + +#include "mongo/base/string_data.h" + +// NOTE: You almost certainly don't want to include this file directly. Instead, access this +// information via the VersionInfoInterface singleton. To enforce this restriction we only allow +// inclusion of this file from files that have explicitly whitelisted it. Additionally, since this +// file is only ever included in .cpp files, it makes some sense to use an unnamed namespace here. + +#ifndef MONGO_UTIL_VERSION_CONSTANTS_H_WHITELISTED +#error "Cannot include mongo/util/version_constants.h" +#endif + +namespace mongo { +namespace version { +namespace { + +constexpr auto kVersion = "@mongo_version@"_sd; +constexpr int kMajorVersion = @mongo_version_major@; +constexpr int kMinorVersion = @mongo_version_minor@; +constexpr int kPatchVersion = @mongo_version_patch@; +constexpr int kExtraVersion = @mongo_version_extra@; +constexpr auto kVersionExtraStr = "@mongo_version_extra_str@"_sd; +constexpr auto kGitVersion = "@mongo_git_hash@"_sd; +constexpr auto kAllocator = "@buildinfo_allocator@"_sd; +constexpr auto kJsEngine = "@buildinfo_js_engine@"_sd; + +// TODO: In C++14, make these constexpr too. +const std::initializer_list<StringData> kModulesList = @buildinfo_modules@; +const std::initializer_list<VersionInfoInterface::BuildInfoTuple> kBuildEnvironment = + @buildinfo_environment_data@; + +} // namespace +} // namespace version +} // namespace mongo diff --git a/src/mongo/util/version_impl.cpp b/src/mongo/util/version_impl.cpp new file mode 100644 index 00000000000..e9226ac6f24 --- /dev/null +++ b/src/mongo/util/version_impl.cpp @@ -0,0 +1,112 @@ +/* Copyright 2016 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/>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the GNU Affero General Public License in all respects + * for all of the code used other than as permitted herein. If you modify + * file(s) with this exception, you may extend this exception to your + * version of the file(s), but you are not obligated to do so. If you do not + * wish to do so, delete this exception statement from your version. If you + * delete this exception statement from all source files in the program, + * then also delete it in the license file. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kControl + +#include "mongo/platform/basic.h" + +#include "mongo/util/version.h" + +#include "mongo/base/init.h" +#include "mongo/util/assert_util.h" +#include "mongo/util/log.h" + +#define MONGO_UTIL_VERSION_CONSTANTS_H_WHITELISTED +#include "mongo/util/version_constants.h" + +namespace mongo { +namespace { + +const class : public VersionInfoInterface { +public: + int majorVersion() const noexcept final { + return version::kMajorVersion; + } + + int minorVersion() const noexcept final { + return version::kMinorVersion; + } + + int patchVersion() const noexcept final { + return version::kPatchVersion; + } + + int extraVersion() const noexcept final { + return version::kExtraVersion; + } + + StringData version() const noexcept final { + return version::kVersion; + } + + StringData gitVersion() const noexcept final { + return version::kGitVersion; + } + + std::vector<StringData> modules() const final { + return version::kModulesList; + } + + StringData allocator() const noexcept final { + return version::kAllocator; + } + + StringData jsEngine() const noexcept final { + return version::kJsEngine; + } + + StringData targetMinOS() const noexcept final { +#if defined(_WIN32) +#if (NTDDI_VERSION >= NTDDI_WIN7) + return "Windows 7/Windows Server 2008 R2"; +#elif (NTDDI_VERSION >= NTDDI_VISTA) + return "Windows Vista/Windows Server 2008"; +#else +#error This targeted Windows version is not supported +#endif // NTDDI_VERSION +#else + severe() << "VersionInfoInterface::targetMinOS is only available for Windows"; + fassertFailed(40277); +#endif + } + + std::vector<BuildInfoTuple> buildInfo() const final { + return version::kBuildEnvironment; + } + +} kInterpolatedVersionInfo{}; + +MONGO_INITIALIZER_GENERAL(EnableVersionInfo, + MONGO_NO_PREREQUISITES, + ("BeginStartupOptionRegistration", "GlobalLogManager")) +(InitializerContext*) { + VersionInfoInterface::enable(&kInterpolatedVersionInfo); + return Status::OK(); +} + +} // namespace +} // namespace mongo |