diff options
-rw-r--r-- | src/mongo/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/SConscript | 15 | ||||
-rw-r--r-- | src/mongo/db/auth/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/commands/SConscript | 61 | ||||
-rw-r--r-- | src/mongo/db/commands/dbcommands.cpp | 255 | ||||
-rw-r--r-- | src/mongo/db/commands/dbcommands_d.cpp | 363 | ||||
-rw-r--r-- | src/mongo/db/commands/generic.cpp | 187 | ||||
-rw-r--r-- | src/mongo/db/commands/generic_servers.cpp | 193 | ||||
-rw-r--r-- | src/mongo/db/ftdc/SConscript | 3 | ||||
-rw-r--r-- | src/mongo/db/repl/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/db/s/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/db/storage/mmap_v1/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/s/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/s/write_ops/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/util/SConscript | 1 |
15 files changed, 607 insertions, 480 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript index 500cf0f8eac..c7d8a7ac98d 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -422,6 +422,7 @@ mongos = env.Program( LIBDEPS=[ 'db/auth/authmongos', 'db/commands/server_status', + 'db/commands/server_status_core', 'db/curop', 'db/ftdc/ftdc_mongos', 'db/logical_time_metadata_hook', diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index de154654219..5382ff524bd 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -532,16 +532,11 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/base', - '$BUILD_DIR/mongo/bson/mutable/mutable_bson', - '$BUILD_DIR/mongo/db/auth/authcore', - '$BUILD_DIR/mongo/db/wire_version', - '$BUILD_DIR/mongo/rpc/command_status', + ], + LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/rpc/rpc', 'audit', - 'auth/authcore', - 'command_can_run_here', 'commands/server_status_core', - 'service_context', ], ) @@ -783,9 +778,10 @@ env.Library( source=[ "curop_metrics.cpp", ], - LIBDEPS=[ + LIBDEPS_PRIVATE=[ + "commands/server_status_core", "curop", - ], + ] ) env.Library( @@ -958,6 +954,7 @@ env.Library( '$BUILD_DIR/mongo/util/background_job', '$BUILD_DIR/mongo/util/elapsed_tracker', '$BUILD_DIR/third_party/s2/s2', + 'audit', 'background', 'bson/dotted_path_support', 'catalog/collection', diff --git a/src/mongo/db/auth/SConscript b/src/mongo/db/auth/SConscript index eaebe1cc5d2..ccc15db37bb 100644 --- a/src/mongo/db/auth/SConscript +++ b/src/mongo/db/auth/SConscript @@ -156,6 +156,7 @@ env.Library( ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/client/sasl_client', + '$BUILD_DIR/mongo/db/audit', '$BUILD_DIR/mongo/db/commands', '$BUILD_DIR/mongo/db/commands/servers', '$BUILD_DIR/mongo/db/commands/test_commands_enabled', diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index 7ed15fbb86b..52d64c426c7 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -10,7 +10,8 @@ env.Library( source=[ "test_commands_enabled.cpp", ], - LIBDEPS=[ + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/server_parameters', "server_status_core", ] ) @@ -23,7 +24,6 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/base', - '$BUILD_DIR/mongo/util/net/network', ] ) @@ -36,8 +36,13 @@ env.Library( '$BUILD_DIR/mongo/db/commands', ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/auth/authcore', + '$BUILD_DIR/mongo/db/stats/counters', '$BUILD_DIR/mongo/transport/message_compressor', '$BUILD_DIR/mongo/transport/service_executor', + '$BUILD_DIR/mongo/util/net/network', + '$BUILD_DIR/mongo/util/processinfo', + 'server_status_core', ], ) @@ -47,7 +52,9 @@ env.Library( "write_commands/write_commands_common.cpp", ], LIBDEPS=[ + '$BUILD_DIR/mongo/db/auth/authcore', '$BUILD_DIR/mongo/base', + '$BUILD_DIR/mongo/db/auth/authprivilege', '$BUILD_DIR/mongo/db/commands', '$BUILD_DIR/mongo/db/ops/write_ops_parsers', ], @@ -78,6 +85,8 @@ env.Library( "rename_collection_common.cpp", ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/auth/authcore', + '$BUILD_DIR/mongo/db/auth/authprivilege', '$BUILD_DIR/mongo/db/commands', '$BUILD_DIR/mongo/db/commands/test_commands_enabled', '$BUILD_DIR/mongo/db/common', @@ -109,6 +118,7 @@ env.Library( "user_management_commands_common.cpp", ], LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/audit', '$BUILD_DIR/mongo/db/commands', '$BUILD_DIR/mongo/db/commands/test_commands_enabled', '$BUILD_DIR/mongo/db/common', @@ -171,25 +181,16 @@ env.Library( env.Library( target="standalone", source=[ - "clone.cpp", - "clone_collection.cpp", - "collection_to_capped.cpp", - "copydb.cpp", - "copydb_start_commands.cpp", "count_cmd.cpp", "create_indexes.cpp", "current_op.cpp", - "dbcheck.cpp", "dbcommands.cpp", - "dbhash.cpp", "distinct.cpp", - "driverHelpers.cpp", "drop_indexes.cpp", "explain_cmd.cpp", "find_and_modify.cpp", "find_cmd.cpp", "geo_near_cmd.cpp", - "get_last_error.cpp", "getmore_cmd.cpp", "index_filter_commands.cpp", "killcursors_cmd.cpp", @@ -207,37 +208,21 @@ env.Library( ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/base', - '$BUILD_DIR/mongo/client/clientdriver', '$BUILD_DIR/mongo/db/commands', '$BUILD_DIR/mongo/db/ops/write_ops_exec', '$BUILD_DIR/mongo/db/catalog/catalog_helpers', - '$BUILD_DIR/mongo/db/catalog/catalog_impl', - '$BUILD_DIR/mongo/db/catalog/collection', - '$BUILD_DIR/mongo/db/catalog/index_key_validate', - '$BUILD_DIR/mongo/db/cloner', '$BUILD_DIR/mongo/db/command_can_run_here', '$BUILD_DIR/mongo/db/curop_failpoint_helpers', - '$BUILD_DIR/mongo/db/exec/stagedebug_cmd', - '$BUILD_DIR/mongo/db/index/index_access_method', - '$BUILD_DIR/mongo/db/index_d', - '$BUILD_DIR/mongo/db/lasterror', - '$BUILD_DIR/mongo/db/ops/write_ops_parsers', + '$BUILD_DIR/mongo/db/catalog/index_key_validate', '$BUILD_DIR/mongo/db/query_exec', '$BUILD_DIR/mongo/db/repair_database', - '$BUILD_DIR/mongo/db/repl/dbcheck', - '$BUILD_DIR/mongo/db/repl/isself', '$BUILD_DIR/mongo/db/rw_concern_d', - '$BUILD_DIR/mongo/db/server_options_core', - '$BUILD_DIR/mongo/db/stats/serveronly_stats', '$BUILD_DIR/mongo/db/views/views_mongod', - '$BUILD_DIR/mongo/util/icu', 'core', 'current_op_common', 'fsync_locked', 'kill_common', 'list_collections_filter', - 'profile_common', - 'test_commands_enabled', 'write_commands_common', ], ) @@ -247,10 +232,20 @@ env.Library( target="mongod", source=[ "apply_ops_cmd.cpp", + "clone.cpp", + "clone_collection.cpp", + "collection_to_capped.cpp", "compact.cpp", + "copydb.cpp", + "copydb_start_commands.cpp", "cpuload.cpp", + "dbcheck.cpp", + "dbcommands_d.cpp", + "dbhash.cpp", "do_txn_cmd.cpp", + "driverHelpers.cpp", "eval.cpp", + "get_last_error.cpp", "group_cmd.cpp", "haystack.cpp", "kill_op.cpp", @@ -277,16 +272,21 @@ env.Library( '$BUILD_DIR/mongo/db/catalog/catalog_helpers', '$BUILD_DIR/mongo/db/catalog/catalog_impl', '$BUILD_DIR/mongo/db/catalog/index_key_validate', + '$BUILD_DIR/mongo/db/cloner', '$BUILD_DIR/mongo/db/commands', + '$BUILD_DIR/mongo/db/exec/stagedebug_cmd', '$BUILD_DIR/mongo/db/index_d', + '$BUILD_DIR/mongo/db/repl/dbcheck', '$BUILD_DIR/mongo/db/repl/oplog', '$BUILD_DIR/mongo/db/repl/repl_coordinator_interface', '$BUILD_DIR/mongo/db/rw_concern_d', '$BUILD_DIR/mongo/db/s/sharding_catalog_manager', '$BUILD_DIR/mongo/s/sharding_legacy_api', + 'core', 'kill_common', 'mongod_fcv', 'mongod_fsync', + 'profile_common', 'standalone', 'servers', 'test_commands_enabled', @@ -329,7 +329,10 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/db/commands', - ] + ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/auth/authcore', + ], ) env.Library( diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp index 3c8581fd6d4..34e2ed22f5b 100644 --- a/src/mongo/db/commands/dbcommands.cpp +++ b/src/mongo/db/commands/dbcommands.cpp @@ -260,40 +260,6 @@ public: } } cmdRepairDatabase; -/** - * Sets the profiling level, logging/profiling threshold, and logging/profiling sample rate for the - * given database. -*/ -class CmdProfile : public ProfileCmdBase { -public: - CmdProfile() = default; - -protected: - int _applyProfilingLevel(OperationContext* opCtx, - const std::string& dbName, - int profilingLevel) const final { - const bool readOnly = (profilingLevel < 0 || profilingLevel > 2); - const LockMode dbMode = readOnly ? MODE_S : MODE_X; - - AutoGetDb ctx(opCtx, dbName, dbMode); - Database* db = ctx.getDb(); - - auto oldLevel = (db ? db->getProfilingLevel() : serverGlobalParams.defaultProfile); - - if (!readOnly) { - if (!db) { - // When setting the profiling level, create the database if it didn't already exist. - // When just reading the profiling level, we do not create the database. - db = dbHolder().openDb(opCtx, dbName); - } - uassertStatusOK(db->setProfilingLevel(opCtx, profilingLevel)); - } - - return oldLevel; - } - -} cmdProfile; - /* drop collection */ class CmdDrop : public ErrmsgCommandDeprecated { public: @@ -467,177 +433,6 @@ public: } } cmdCreate; -class CmdFileMD5 : public BasicCommand { -public: - CmdFileMD5() : BasicCommand("filemd5") {} - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kAlways; - } - - std::string help() const override { - return " example: { filemd5 : ObjectId(aaaaaaa) , root : \"fs\" }"; - } - - - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - - virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const { - std::string collectionName; - if (const auto rootElt = cmdObj["root"]) { - uassert(ErrorCodes::InvalidNamespace, - "'root' must be of type String", - rootElt.type() == BSONType::String); - collectionName = rootElt.str(); - } - if (collectionName.empty()) - collectionName = "fs"; - collectionName += ".chunks"; - return NamespaceString(dbname, collectionName).ns(); - } - - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), ActionType::find)); - } - - bool run(OperationContext* opCtx, - const string& dbname, - const BSONObj& jsobj, - BSONObjBuilder& result) { - const NamespaceString nss(parseNs(dbname, jsobj)); - - md5digest d; - md5_state_t st; - md5_init(&st); - - int n = 0; - - bool partialOk = jsobj["partialOk"].trueValue(); - if (partialOk) { - // WARNING: This code depends on the binary layout of md5_state. It will not be - // compatible with different md5 libraries or work correctly in an environment with - // mongod's of different endians. It is ok for mongos to be a different endian since - // it just passes the buffer through to another mongod. - BSONElement stateElem = jsobj["md5state"]; - if (!stateElem.eoo()) { - int len; - const char* data = stateElem.binDataClean(len); - massert(16247, "md5 state not correct size", len == sizeof(st)); - memcpy(&st, data, sizeof(st)); - } - n = jsobj["startAt"].numberInt(); - } - - BSONObj query = BSON("files_id" << jsobj["filemd5"] << "n" << GTE << n); - BSONObj sort = BSON("files_id" << 1 << "n" << 1); - - return writeConflictRetry(opCtx, "filemd5", dbname, [&] { - auto qr = stdx::make_unique<QueryRequest>(nss); - qr->setFilter(query); - qr->setSort(sort); - - auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr)); - if (!statusWithCQ.isOK()) { - uasserted(17240, "Can't canonicalize query " + query.toString()); - return false; - } - unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); - - // Check shard version at startup. - // This will throw before we've done any work if shard version is outdated - // We drop and re-acquire these locks every document because md5'ing is expensive - unique_ptr<AutoGetCollectionForReadCommand> ctx( - new AutoGetCollectionForReadCommand(opCtx, nss)); - Collection* coll = ctx->getCollection(); - - auto exec = uassertStatusOK(getExecutor(opCtx, - coll, - std::move(cq), - PlanExecutor::YIELD_MANUAL, - QueryPlannerParams::NO_TABLE_SCAN)); - - BSONObj obj; - PlanExecutor::ExecState state; - while (PlanExecutor::ADVANCED == (state = exec->getNext(&obj, NULL))) { - BSONElement ne = obj["n"]; - verify(ne.isNumber()); - int myn = ne.numberInt(); - if (n != myn) { - if (partialOk) { - break; // skipped chunk is probably on another shard - } - log() << "should have chunk: " << n << " have:" << myn; - dumpChunks(opCtx, nss.ns(), query, sort); - uassert(10040, "chunks out of order", n == myn); - } - - // make a copy of obj since we access data in it while yielding locks - BSONObj owned = obj.getOwned(); - exec->saveState(); - // UNLOCKED - ctx.reset(); - - int len; - const char* data = owned["data"].binDataClean(len); - // This is potentially an expensive operation, so do it out of the lock - md5_append(&st, (const md5_byte_t*)(data), len); - n++; - - try { - // RELOCKED - ctx.reset(new AutoGetCollectionForReadCommand(opCtx, nss)); - } catch (const StaleConfigException&) { - LOG(1) << "chunk metadata changed during filemd5, will retarget and continue"; - break; - } - - // Have the lock again. See if we were killed. - if (!exec->restoreState().isOK()) { - if (!partialOk) { - uasserted(13281, "File deleted during filemd5 command"); - } - } - } - - if (PlanExecutor::DEAD == state || PlanExecutor::FAILURE == state) { - return CommandHelpers::appendCommandStatus( - result, - WorkingSetCommon::getMemberObjectStatus(obj).withContext( - "Executor error during filemd5 command")); - } - - if (partialOk) - result.appendBinData("md5state", sizeof(st), BinDataGeneral, &st); - - // This must be *after* the capture of md5state since it mutates st - md5_finish(&st, d); - - result.append("numChunks", n); - result.append("md5", digestToString(d)); - - return true; - }); - } - - void dumpChunks(OperationContext* opCtx, - const string& ns, - const BSONObj& query, - const BSONObj& sort) { - DBDirectClient client(opCtx); - Query q(query); - q.sort(sort); - unique_ptr<DBClientCursor> c = client.query(ns, q); - while (c->more()) { - log() << c->nextSafe(); - } - } - -} cmdFileMD5; - class CmdDatasize : public ErrmsgCommandDeprecated { virtual string parseNs(const string& dbname, const BSONObj& cmdObj) const { return CommandHelpers::parseNsFullyQualified(cmdObj); @@ -968,55 +763,5 @@ public: } cmdDBStats; -/* Returns client's uri */ -class CmdWhatsMyUri : public BasicCommand { -public: - CmdWhatsMyUri() : BasicCommand("whatsmyuri") {} - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kAlways; - } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - std::string help() const override { - return "{whatsmyuri:1}"; - } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const {} // No auth required - virtual bool run(OperationContext* opCtx, - const string& dbname, - const BSONObj& cmdObj, - BSONObjBuilder& result) { - result << "you" << opCtx->getClient()->clientAddress(true /*includePort*/); - return true; - } -} cmdWhatsMyUri; - -class AvailableQueryOptions : public BasicCommand { -public: - AvailableQueryOptions() : BasicCommand("availableQueryOptions", "availablequeryoptions") {} - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kAlways; - } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - virtual Status checkAuthForCommand(Client* client, - const std::string& dbname, - const BSONObj& cmdObj) const { - return Status::OK(); - } - - virtual bool run(OperationContext* opCtx, - const string& dbname, - const BSONObj& cmdObj, - BSONObjBuilder& result) { - result << "options" << QueryOption_AllSupported; - return true; - } -} availableQueryOptionsCmd; - } // namespace } // namespace mongo diff --git a/src/mongo/db/commands/dbcommands_d.cpp b/src/mongo/db/commands/dbcommands_d.cpp new file mode 100644 index 00000000000..44de9bbc2c4 --- /dev/null +++ b/src/mongo/db/commands/dbcommands_d.cpp @@ -0,0 +1,363 @@ +/** + * Copyright (C) 2012-2015 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. + */ + +#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand + +#include "mongo/platform/basic.h" + +#include <time.h> + +#include "mongo/base/simple_string_data_comparator.h" +#include "mongo/base/status_with.h" +#include "mongo/bson/simple_bsonobj_comparator.h" +#include "mongo/bson/util/bson_extract.h" +#include "mongo/bson/util/builder.h" +#include "mongo/db/audit.h" +#include "mongo/db/auth/action_set.h" +#include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/authorization_manager.h" +#include "mongo/db/auth/authorization_session.h" +#include "mongo/db/auth/privilege.h" +#include "mongo/db/auth/user_management_commands_parser.h" +#include "mongo/db/auth/user_name.h" +#include "mongo/db/background.h" +#include "mongo/db/catalog/coll_mod.h" +#include "mongo/db/catalog/create_collection.h" +#include "mongo/db/catalog/database_holder.h" +#include "mongo/db/catalog/drop_collection.h" +#include "mongo/db/catalog/drop_database.h" +#include "mongo/db/catalog/index_key_validate.h" +#include "mongo/db/catalog_raii.h" +#include "mongo/db/clientcursor.h" +#include "mongo/db/commands.h" +#include "mongo/db/commands/profile_common.h" +#include "mongo/db/commands/profile_gen.h" +#include "mongo/db/commands/server_status.h" +#include "mongo/db/concurrency/write_conflict_exception.h" +#include "mongo/db/db_raii.h" +#include "mongo/db/dbdirectclient.h" +#include "mongo/db/dbhelpers.h" +#include "mongo/db/exec/working_set_common.h" +#include "mongo/db/index/index_access_method.h" +#include "mongo/db/index/index_descriptor.h" +#include "mongo/db/index_builder.h" +#include "mongo/db/introspect.h" +#include "mongo/db/jsobj.h" +#include "mongo/db/json.h" +#include "mongo/db/keypattern.h" +#include "mongo/db/lasterror.h" +#include "mongo/db/namespace_string.h" +#include "mongo/db/op_observer.h" +#include "mongo/db/ops/insert.h" +#include "mongo/db/query/collation/collator_factory_interface.h" +#include "mongo/db/query/get_executor.h" +#include "mongo/db/query/internal_plans.h" +#include "mongo/db/query/query_planner.h" +#include "mongo/db/read_concern.h" +#include "mongo/db/repair_database.h" +#include "mongo/db/repl/optime.h" +#include "mongo/db/repl/read_concern_args.h" +#include "mongo/db/repl/repl_client_info.h" +#include "mongo/db/repl/repl_settings.h" +#include "mongo/db/repl/replication_coordinator.h" +#include "mongo/db/server_parameters.h" +#include "mongo/db/stats/storage_stats.h" +#include "mongo/db/write_concern.h" +#include "mongo/s/stale_exception.h" +#include "mongo/scripting/engine.h" +#include "mongo/util/fail_point_service.h" +#include "mongo/util/log.h" +#include "mongo/util/md5.hpp" +#include "mongo/util/scopeguard.h" + +namespace mongo { + +using std::ostringstream; +using std::string; +using std::stringstream; +using std::unique_ptr; + +namespace { + +/** + * Sets the profiling level, logging/profiling threshold, and logging/profiling sample rate for the + * given database. +*/ +class CmdProfile : public ProfileCmdBase { +public: + CmdProfile() = default; + +protected: + int _applyProfilingLevel(OperationContext* opCtx, + const std::string& dbName, + int profilingLevel) const final { + const bool readOnly = (profilingLevel < 0 || profilingLevel > 2); + const LockMode dbMode = readOnly ? MODE_S : MODE_X; + + AutoGetDb ctx(opCtx, dbName, dbMode); + Database* db = ctx.getDb(); + + auto oldLevel = (db ? db->getProfilingLevel() : serverGlobalParams.defaultProfile); + + if (!readOnly) { + if (!db) { + // When setting the profiling level, create the database if it didn't already exist. + // When just reading the profiling level, we do not create the database. + db = dbHolder().openDb(opCtx, dbName); + } + uassertStatusOK(db->setProfilingLevel(opCtx, profilingLevel)); + } + + return oldLevel; + } + +} cmdProfile; + +class CmdFileMD5 : public BasicCommand { +public: + CmdFileMD5() : BasicCommand("filemd5") {} + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + + std::string help() const override { + return " example: { filemd5 : ObjectId(aaaaaaa) , root : \"fs\" }"; + } + + + virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + + virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const { + std::string collectionName; + if (const auto rootElt = cmdObj["root"]) { + uassert(ErrorCodes::InvalidNamespace, + "'root' must be of type String", + rootElt.type() == BSONType::String); + collectionName = rootElt.str(); + } + if (collectionName.empty()) + collectionName = "fs"; + collectionName += ".chunks"; + return NamespaceString(dbname, collectionName).ns(); + } + + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) const { + out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), ActionType::find)); + } + + bool run(OperationContext* opCtx, + const string& dbname, + const BSONObj& jsobj, + BSONObjBuilder& result) { + const NamespaceString nss(parseNs(dbname, jsobj)); + + md5digest d; + md5_state_t st; + md5_init(&st); + + int n = 0; + + bool partialOk = jsobj["partialOk"].trueValue(); + if (partialOk) { + // WARNING: This code depends on the binary layout of md5_state. It will not be + // compatible with different md5 libraries or work correctly in an environment with + // mongod's of different endians. It is ok for mongos to be a different endian since + // it just passes the buffer through to another mongod. + BSONElement stateElem = jsobj["md5state"]; + if (!stateElem.eoo()) { + int len; + const char* data = stateElem.binDataClean(len); + massert(16247, "md5 state not correct size", len == sizeof(st)); + memcpy(&st, data, sizeof(st)); + } + n = jsobj["startAt"].numberInt(); + } + + BSONObj query = BSON("files_id" << jsobj["filemd5"] << "n" << GTE << n); + BSONObj sort = BSON("files_id" << 1 << "n" << 1); + + return writeConflictRetry(opCtx, "filemd5", dbname, [&] { + auto qr = stdx::make_unique<QueryRequest>(nss); + qr->setFilter(query); + qr->setSort(sort); + + auto statusWithCQ = CanonicalQuery::canonicalize(opCtx, std::move(qr)); + if (!statusWithCQ.isOK()) { + uasserted(17240, "Can't canonicalize query " + query.toString()); + return false; + } + unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue()); + + // Check shard version at startup. + // This will throw before we've done any work if shard version is outdated + // We drop and re-acquire these locks every document because md5'ing is expensive + unique_ptr<AutoGetCollectionForReadCommand> ctx( + new AutoGetCollectionForReadCommand(opCtx, nss)); + Collection* coll = ctx->getCollection(); + + auto exec = uassertStatusOK(getExecutor(opCtx, + coll, + std::move(cq), + PlanExecutor::YIELD_MANUAL, + QueryPlannerParams::NO_TABLE_SCAN)); + + BSONObj obj; + PlanExecutor::ExecState state; + while (PlanExecutor::ADVANCED == (state = exec->getNext(&obj, NULL))) { + BSONElement ne = obj["n"]; + verify(ne.isNumber()); + int myn = ne.numberInt(); + if (n != myn) { + if (partialOk) { + break; // skipped chunk is probably on another shard + } + log() << "should have chunk: " << n << " have:" << myn; + dumpChunks(opCtx, nss.ns(), query, sort); + uassert(10040, "chunks out of order", n == myn); + } + + // make a copy of obj since we access data in it while yielding locks + BSONObj owned = obj.getOwned(); + exec->saveState(); + // UNLOCKED + ctx.reset(); + + int len; + const char* data = owned["data"].binDataClean(len); + // This is potentially an expensive operation, so do it out of the lock + md5_append(&st, (const md5_byte_t*)(data), len); + n++; + + try { + // RELOCKED + ctx.reset(new AutoGetCollectionForReadCommand(opCtx, nss)); + } catch (const StaleConfigException&) { + LOG(1) << "chunk metadata changed during filemd5, will retarget and continue"; + break; + } + + // Have the lock again. See if we were killed. + if (!exec->restoreState().isOK()) { + if (!partialOk) { + uasserted(13281, "File deleted during filemd5 command"); + } + } + } + + if (PlanExecutor::DEAD == state || PlanExecutor::FAILURE == state) { + return CommandHelpers::appendCommandStatus( + result, + WorkingSetCommon::getMemberObjectStatus(obj).withContext( + "Executor error during filemd5 command")); + } + + if (partialOk) + result.appendBinData("md5state", sizeof(st), BinDataGeneral, &st); + + // This must be *after* the capture of md5state since it mutates st + md5_finish(&st, d); + + result.append("numChunks", n); + result.append("md5", digestToString(d)); + + return true; + }); + } + + void dumpChunks(OperationContext* opCtx, + const string& ns, + const BSONObj& query, + const BSONObj& sort) { + DBDirectClient client(opCtx); + Query q(query); + q.sort(sort); + unique_ptr<DBClientCursor> c = client.query(ns, q); + while (c->more()) { + log() << c->nextSafe(); + } + } + +} cmdFileMD5; + +/* Returns client's uri */ +class CmdWhatsMyUri : public BasicCommand { +public: + CmdWhatsMyUri() : BasicCommand("whatsmyuri") {} + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + std::string help() const override { + return "{whatsmyuri:1}"; + } + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) const {} // No auth required + virtual bool run(OperationContext* opCtx, + const string& dbname, + const BSONObj& cmdObj, + BSONObjBuilder& result) { + result << "you" << opCtx->getClient()->clientAddress(true /*includePort*/); + return true; + } +} cmdWhatsMyUri; + +class AvailableQueryOptions : public BasicCommand { +public: + AvailableQueryOptions() : BasicCommand("availableQueryOptions", "availablequeryoptions") {} + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + virtual Status checkAuthForCommand(Client* client, + const std::string& dbname, + const BSONObj& cmdObj) const { + return Status::OK(); + } + + virtual bool run(OperationContext* opCtx, + const string& dbname, + const BSONObj& cmdObj, + BSONObjBuilder& result) { + result << "options" << QueryOption_AllSupported; + return true; + } +} availableQueryOptionsCmd; + +} // namespace +} // namespace mongo diff --git a/src/mongo/db/commands/generic.cpp b/src/mongo/db/commands/generic.cpp index ccb09698095..20a5c03543e 100644 --- a/src/mongo/db/commands/generic.cpp +++ b/src/mongo/db/commands/generic.cpp @@ -116,37 +116,6 @@ public: } } pingCmd; -class LogRotateCmd : public BasicCommand { -public: - LogRotateCmd() : BasicCommand("logRotate") {} - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kAlways; - } - bool adminOnly() const override { - return true; - } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::logRotate); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); - } - virtual bool run(OperationContext* opCtx, - const string& ns, - const BSONObj& cmdObj, - BSONObjBuilder& result) { - bool didRotate = rotateLogs(serverGlobalParams.logRenameOnRotate); - if (didRotate) - logProcessDetailsForLogRotate(opCtx->getServiceContext()); - return didRotate; - } - -} logRotateCmd; - class ListCommandsCmd : public BasicCommand { public: std::string help() const override { @@ -201,161 +170,5 @@ public: } listCommandsCmd; -class GetLogCmd : public ErrmsgCommandDeprecated { -public: - GetLogCmd() : ErrmsgCommandDeprecated("getLog") {} - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kAlways; - } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - virtual bool adminOnly() const { - return true; - } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::getLog); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); - } - std::string help() const override { - return "{ getLog : '*' } OR { getLog : 'global' }"; - } - - virtual bool errmsgRun(OperationContext* opCtx, - const string& dbname, - const BSONObj& cmdObj, - string& errmsg, - BSONObjBuilder& result) { - BSONElement val = cmdObj.firstElement(); - if (val.type() != String) { - return CommandHelpers::appendCommandStatus( - result, - Status(ErrorCodes::TypeMismatch, - str::stream() << "Argument to getLog must be of type String; found " - << val.toString(false) - << " of type " - << typeName(val.type()))); - } - - string p = val.String(); - if (p == "*") { - vector<string> names; - RamLog::getNames(names); - - BSONArrayBuilder arr; - for (unsigned i = 0; i < names.size(); i++) { - arr.append(names[i]); - } - - result.appendArray("names", arr.arr()); - } else { - RamLog* ramlog = RamLog::getIfExists(p); - if (!ramlog) { - errmsg = str::stream() << "no RamLog named: " << p; - return false; - } - RamLog::LineIterator rl(ramlog); - - result.appendNumber("totalLinesWritten", rl.getTotalLinesWritten()); - - BSONArrayBuilder arr(result.subarrayStart("log")); - while (rl.more()) - arr.append(rl.next()); - arr.done(); - } - return true; - } - -} getLogCmd; - -class ClearLogCmd : public BasicCommand { -public: - ClearLogCmd() : BasicCommand("clearLog") {} - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kAlways; - } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - virtual bool adminOnly() const { - return true; - } - Status checkAuthForCommand(Client* client, - const std::string& dbname, - const BSONObj& cmdObj) const override { - // No access control needed since this command is a testing-only command that must be - // enabled at the command line. - return Status::OK(); - } - std::string help() const override { - return "{ clearLog : 'global' }"; - } - - virtual bool run(OperationContext* opCtx, - const string& dbname, - const BSONObj& cmdObj, - BSONObjBuilder& result) { - std::string logName; - Status status = bsonExtractStringField(cmdObj, "clearLog", &logName); - if (!status.isOK()) { - return CommandHelpers::appendCommandStatus(result, status); - } - - if (logName != "global") { - return CommandHelpers::appendCommandStatus( - result, Status(ErrorCodes::InvalidOptions, "Only the 'global' log can be cleared")); - } - RamLog* ramlog = RamLog::getIfExists(logName); - invariant(ramlog); - ramlog->clear(); - return true; - } -}; - -MONGO_INITIALIZER(RegisterClearLogCmd)(InitializerContext* context) { - if (getTestCommandsEnabled()) { - // Leaked intentionally: a Command registers itself when constructed. - new ClearLogCmd(); - } - return Status::OK(); -} - -class CmdGetCmdLineOpts : public BasicCommand { -public: - CmdGetCmdLineOpts() : BasicCommand("getCmdLineOpts") {} - std::string help() const override { - return "get argv"; - } - virtual bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - virtual bool adminOnly() const { - return true; - } - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kAlways; - } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const { - ActionSet actions; - actions.addAction(ActionType::getCmdLineOpts); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); - } - virtual bool run(OperationContext* opCtx, - const string&, - const BSONObj& cmdObj, - BSONObjBuilder& result) { - result.append("argv", serverGlobalParams.argvArray); - result.append("parsed", serverGlobalParams.parsedOpts); - return true; - } - -} cmdGetCmdLineOpts; } // namespace } // namespace mongo diff --git a/src/mongo/db/commands/generic_servers.cpp b/src/mongo/db/commands/generic_servers.cpp index d003ea1c7f1..261562894a2 100644 --- a/src/mongo/db/commands/generic_servers.cpp +++ b/src/mongo/db/commands/generic_servers.cpp @@ -30,9 +30,12 @@ #include "mongo/platform/basic.h" +#include "mongo/bson/util/bson_extract.h" #include "mongo/bson/util/builder.h" #include "mongo/db/commands.h" #include "mongo/db/commands/shutdown.h" +#include "mongo/db/commands/test_commands_enabled.h" +#include "mongo/db/log_process_details.h" #include "mongo/scripting/engine.h" #include "mongo/util/exit.h" #include "mongo/util/fail_point.h" @@ -41,6 +44,7 @@ #include "mongo/util/net/sock.h" #include "mongo/util/ntservice.h" #include "mongo/util/processinfo.h" +#include "mongo/util/ramlog.h" #include <string> #include <vector> @@ -49,6 +53,7 @@ namespace mongo { namespace { using std::string; +using std::vector; class FeaturesCmd : public BasicCommand { public: @@ -136,6 +141,194 @@ public: MONGO_FP_DECLARE(crashOnShutdown); int* volatile illegalAddress; // NOLINT - used for fail point only +class CmdGetCmdLineOpts : public BasicCommand { +public: + CmdGetCmdLineOpts() : BasicCommand("getCmdLineOpts") {} + std::string help() const override { + return "get argv"; + } + virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + virtual bool adminOnly() const { + return true; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) const { + ActionSet actions; + actions.addAction(ActionType::getCmdLineOpts); + out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + } + virtual bool run(OperationContext* opCtx, + const string&, + const BSONObj& cmdObj, + BSONObjBuilder& result) { + result.append("argv", serverGlobalParams.argvArray); + result.append("parsed", serverGlobalParams.parsedOpts); + return true; + } + +} cmdGetCmdLineOpts; + +class LogRotateCmd : public BasicCommand { +public: + LogRotateCmd() : BasicCommand("logRotate") {} + virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + bool adminOnly() const override { + return true; + } + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) const { + ActionSet actions; + actions.addAction(ActionType::logRotate); + out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + } + virtual bool run(OperationContext* opCtx, + const string& ns, + const BSONObj& cmdObj, + BSONObjBuilder& result) { + bool didRotate = rotateLogs(serverGlobalParams.logRenameOnRotate); + if (didRotate) + logProcessDetailsForLogRotate(opCtx->getServiceContext()); + return didRotate; + } + +} logRotateCmd; + +class GetLogCmd : public ErrmsgCommandDeprecated { +public: + GetLogCmd() : ErrmsgCommandDeprecated("getLog") {} + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + virtual bool adminOnly() const { + return true; + } + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) const { + ActionSet actions; + actions.addAction(ActionType::getLog); + out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + } + std::string help() const override { + return "{ getLog : '*' } OR { getLog : 'global' }"; + } + + virtual bool errmsgRun(OperationContext* opCtx, + const string& dbname, + const BSONObj& cmdObj, + string& errmsg, + BSONObjBuilder& result) { + BSONElement val = cmdObj.firstElement(); + if (val.type() != String) { + return CommandHelpers::appendCommandStatus( + result, + Status(ErrorCodes::TypeMismatch, + str::stream() << "Argument to getLog must be of type String; found " + << val.toString(false) + << " of type " + << typeName(val.type()))); + } + + string p = val.String(); + if (p == "*") { + vector<string> names; + RamLog::getNames(names); + + BSONArrayBuilder arr; + for (unsigned i = 0; i < names.size(); i++) { + arr.append(names[i]); + } + + result.appendArray("names", arr.arr()); + } else { + RamLog* ramlog = RamLog::getIfExists(p); + if (!ramlog) { + errmsg = str::stream() << "no RamLog named: " << p; + return false; + } + RamLog::LineIterator rl(ramlog); + + result.appendNumber("totalLinesWritten", rl.getTotalLinesWritten()); + + BSONArrayBuilder arr(result.subarrayStart("log")); + while (rl.more()) + arr.append(rl.next()); + arr.done(); + } + return true; + } + +} getLogCmd; + +class ClearLogCmd : public BasicCommand { +public: + ClearLogCmd() : BasicCommand("clearLog") {} + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + virtual bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + virtual bool adminOnly() const { + return true; + } + Status checkAuthForCommand(Client* client, + const std::string& dbname, + const BSONObj& cmdObj) const override { + // No access control needed since this command is a testing-only command that must be + // enabled at the command line. + return Status::OK(); + } + std::string help() const override { + return "{ clearLog : 'global' }"; + } + + virtual bool run(OperationContext* opCtx, + const string& dbname, + const BSONObj& cmdObj, + BSONObjBuilder& result) { + std::string logName; + Status status = bsonExtractStringField(cmdObj, "clearLog", &logName); + if (!status.isOK()) { + return CommandHelpers::appendCommandStatus(result, status); + } + + if (logName != "global") { + return CommandHelpers::appendCommandStatus( + result, Status(ErrorCodes::InvalidOptions, "Only the 'global' log can be cleared")); + } + RamLog* ramlog = RamLog::getIfExists(logName); + invariant(ramlog); + ramlog->clear(); + return true; + } +}; + +MONGO_INITIALIZER(RegisterClearLogCmd)(InitializerContext* context) { + if (getTestCommandsEnabled()) { + // Leaked intentionally: a Command registers itself when constructed. + new ClearLogCmd(); + } + return Status::OK(); +} + } // namespace void CmdShutdown::addRequiredPrivileges(const std::string& dbname, diff --git a/src/mongo/db/ftdc/SConscript b/src/mongo/db/ftdc/SConscript index 68ff033a2d2..fd84a46cdb3 100644 --- a/src/mongo/db/ftdc/SConscript +++ b/src/mongo/db/ftdc/SConscript @@ -68,6 +68,9 @@ env.Library( '$BUILD_DIR/mongo/db/storage/storage_options', 'ftdc_server' ], + LIBDEPS_PRIVATE=[ + '$BUILD_DIR/mongo/db/auth/authcore', + ], ) env.Library( diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript index 18437a1a2c7..bcb0da9d789 100644 --- a/src/mongo/db/repl/SConscript +++ b/src/mongo/db/repl/SConscript @@ -1452,6 +1452,7 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/client/fetcher', + '$BUILD_DIR/mongo/db/commands/server_status_core', 'collection_cloner', 'database_cloner', 'databases_cloner', diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript index 963cde5b133..9f3806c45f8 100644 --- a/src/mongo/db/s/SConscript +++ b/src/mongo/db/s/SConscript @@ -155,6 +155,7 @@ env.Library( '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/bson/util/bson_extract', '$BUILD_DIR/mongo/db/common', + '$BUILD_DIR/mongo/db/repl/repl_coordinator_interface', '$BUILD_DIR/mongo/s/catalog/dist_lock_manager', '$BUILD_DIR/mongo/s/client/sharding_client', '$BUILD_DIR/mongo/s/coreshard', @@ -188,6 +189,7 @@ env.Library( 'config/sharding_catalog_manager_zone_operations.cpp', ], LIBDEPS=[ + '$BUILD_DIR/mongo/db/audit', '$BUILD_DIR/mongo/db/catalog/collection_options', '$BUILD_DIR/mongo/db/catalog_raii', '$BUILD_DIR/mongo/db/repl/read_concern_args', diff --git a/src/mongo/db/storage/mmap_v1/SConscript b/src/mongo/db/storage/mmap_v1/SConscript index 748fadad43e..4d7bf2b5f87 100644 --- a/src/mongo/db/storage/mmap_v1/SConscript +++ b/src/mongo/db/storage/mmap_v1/SConscript @@ -167,6 +167,7 @@ env.Library( 'touch_pages.cpp', ], LIBDEPS= [ + '$BUILD_DIR/mongo/db/commands/server_status_core', '$BUILD_DIR/mongo/db/curop', '$BUILD_DIR/mongo/db/service_context', '$BUILD_DIR/mongo/db/storage/storage_options', diff --git a/src/mongo/s/SConscript b/src/mongo/s/SConscript index b16e81b30a3..58482ba0735 100644 --- a/src/mongo/s/SConscript +++ b/src/mongo/s/SConscript @@ -74,6 +74,7 @@ env.Library( ], LIBDEPS=[ '$BUILD_DIR/mongo/db/logical_session_cache_factory_mongos', + '$BUILD_DIR/mongo/db/repl/repl_coordinator_interface', '$BUILD_DIR/mongo/executor/network_interface_factory', '$BUILD_DIR/mongo/executor/network_interface_thread_pool', '$BUILD_DIR/mongo/executor/thread_pool_task_executor', @@ -331,6 +332,7 @@ env.Library( 'sharding_egress_metadata_hook.cpp', ], LIBDEPS=[ + '$BUILD_DIR/mongo/db/audit', '$BUILD_DIR/mongo/util/concurrency/thread_pool', 'grid', ], diff --git a/src/mongo/s/write_ops/SConscript b/src/mongo/s/write_ops/SConscript index 62157927897..b9dda858343 100644 --- a/src/mongo/s/write_ops/SConscript +++ b/src/mongo/s/write_ops/SConscript @@ -18,6 +18,7 @@ env.Library( '$BUILD_DIR/mongo/db/ops/write_ops_parsers', '$BUILD_DIR/mongo/db/repl/optime', '$BUILD_DIR/mongo/db/commands', + '$BUILD_DIR/mongo/rpc/command_status', '$BUILD_DIR/mongo/s/common_s', ], ) diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript index 594e415d2c1..43e58dd2dce 100644 --- a/src/mongo/util/SConscript +++ b/src/mongo/util/SConscript @@ -348,6 +348,7 @@ if env['MONGO_ALLOCATOR'] == 'tcmalloc': ], LIBDEPS_PRIVATE=[ '$BUILD_DIR/mongo/db/commands/server_status', + 'processinfo', ], LIBDEPS_DEPENDENTS=[ '$BUILD_DIR/mongo/mongodmain', |