From fe0d238b0ac31f4b2294bda827cc913d59d6de57 Mon Sep 17 00:00:00 2001 From: Spencer T Brody Date: Tue, 4 Dec 2012 18:11:25 -0500 Subject: SERVER-7122 Add setParameter option to enable/disable testing commands --- src/mongo/db/cloner.cpp | 2 +- src/mongo/db/commands.cpp | 11 +++++ src/mongo/db/commands.h | 2 + src/mongo/db/commands/hashcmd.cpp | 16 ++++++- src/mongo/db/dbcommands.cpp | 80 ++++++++++++++++++++++------------ src/mongo/db/dbcommands_admin.cpp | 20 +++++++-- src/mongo/db/repl/replset_commands.cpp | 17 +++++++- 7 files changed, 113 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index 30d75979bff..a3a6357cc38 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -775,7 +775,7 @@ namespace mongo { } }; - MONGO_INITIALIZER(RegisterGodInsertCmd)(InitializerContext* context) { + MONGO_INITIALIZER(RegisterNotWithAuthCommands)(InitializerContext* context) { if (noauth) { // Leaked intentionally: a Command registers itself when constructed. new CmdClone(); diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp index e1f505115ab..5f8a13c51a4 100755 --- a/src/mongo/db/commands.cpp +++ b/src/mongo/db/commands.cpp @@ -31,6 +31,7 @@ #include "mongo/db/client.h" #include "mongo/db/jsobj.h" #include "mongo/db/replutil.h" +#include "mongo/db/server_parameters.h" namespace mongo { @@ -38,6 +39,16 @@ namespace mongo { map * Command::_webCommands; map * Command::_commands; + // TODO: set to 0 once tests have been updated to enable this + int Command::testCommandsEnabled = 1; + + namespace { + // TODO: This should only be settable at the command line, not at runtime. Need SERVER-7778 + ExportedServerParameter testCommandsParameter(ServerParameterSet::getGlobal(), + "enableTestCommands", + &Command::testCommandsEnabled); + } + string Command::parseNsFullyQualified(const string& dbname, const BSONObj& cmdObj) const { string s = cmdObj.firstElement().valuestr(); NamespaceString nss(s); diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index d02949a6ebc..42161a899ce 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -159,6 +159,8 @@ namespace mongo { static bool runAgainstRegistered(const char *ns, BSONObj& jsobj, BSONObjBuilder& anObjBuilder, int queryOptions = 0); static LockType locktype( const string& name ); static Command * findCommand( const string& name ); + // Set by command line. Controls whether or not testing-only commands should be available. + static int testCommandsEnabled; }; class CmdShutdown : public Command { diff --git a/src/mongo/db/commands/hashcmd.cpp b/src/mongo/db/commands/hashcmd.cpp index 043ab37a77b..acf4000505e 100644 --- a/src/mongo/db/commands/hashcmd.cpp +++ b/src/mongo/db/commands/hashcmd.cpp @@ -23,6 +23,8 @@ #include #include +#include "mongo/base/init.h" +#include "mongo/base/status.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_manager.h" @@ -33,14 +35,17 @@ namespace mongo { + // Testing only, enabled via command-line. class CmdHashElt : public Command { public: CmdHashElt() : Command("_hashBSONElement") {}; virtual LockType locktype() const { return NONE; } virtual bool slaveOk() const { return true; } + // No auth needed because it only works when enabled via command line. + virtual bool requiresAuth() { return false; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, - std::vector* out) {} // No auth required + std::vector* out) {} virtual void help( stringstream& help ) const { help << "returns the hash of the first BSONElement val in a BSONObj"; } @@ -77,5 +82,12 @@ namespace mongo { result.append( "out" , BSONElementHasher::hash64( cmdObj.firstElement() , seed ) ); return true; } - } cmdHashElt; + }; + MONGO_INITIALIZER(RegisterHashEltCmd)(InitializerContext* context) { + if (Command::testCommandsEnabled) { + // Leaked intentionally: a Command registers itself when constructed. + new CmdHashElt(); + } + return Status::OK(); + } } diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index ff57ace9a88..8f962b27325 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -25,6 +25,8 @@ #include +#include "mongo/base/init.h" +#include "mongo/base/status.h" #include "mongo/bson/util/builder.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" @@ -1597,7 +1599,7 @@ namespace mongo { } } cmdWhatsMyUri; - /* For testing only, not for general use */ + /* For testing only, not for general use. Enabled via command-line */ class GodInsert : public Command { public: GodInsert() : Command( "godinsert" ) { } @@ -1605,14 +1607,14 @@ namespace mongo { virtual bool logTheOp() { return false; } virtual bool slaveOk() const { return true; } virtual LockType locktype() const { return NONE; } - virtual bool requiresAuth() { return true; } - virtual void help( stringstream &help ) const { - help << "internal. for testing only."; - } - // No auth required, only enabled via command line for testing + // No auth needed because it only works when enabled via command line. + virtual bool requiresAuth() { return false; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector* out) {} + virtual void help( stringstream &help ) const { + help << "internal. for testing only."; + } virtual bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { AuthenticationInfo *ai = cc().getAuthenticationInfo(); @@ -1633,7 +1635,15 @@ namespace mongo { } return true; } - } cmdGodInsert; + }; + + MONGO_INITIALIZER(RegisterGodInsertCmd)(InitializerContext* context) { + if (Command::testCommandsEnabled) { + // Leaked intentionally: a Command registers itself when constructed. + new GodInsert(); + } + return Status::OK(); + } class DBHashCmd : public Command { public: @@ -1733,7 +1743,7 @@ namespace mongo { } dbhashCmd; - /* for diagnostic / testing purposes. */ + /* for diagnostic / testing purposes. Enabled via command line. */ class CmdSleep : public Command { public: virtual LockType locktype() const { return NONE; } @@ -1744,7 +1754,8 @@ namespace mongo { help << "internal testing command. Makes db block (in a read lock) for 100 seconds\n"; help << "w:true write lock. secs:"; } - // No auth required, only enabled via command line for testing + // No auth needed because it only works when enabled via command line. + virtual bool requiresAuth() { return false; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, std::vector* out) {} @@ -1764,23 +1775,26 @@ namespace mongo { } return true; } - } cmdSleep; + }; + MONGO_INITIALIZER(RegisterSleepCmd)(InitializerContext* context) { + if (Command::testCommandsEnabled) { + // Leaked intentionally: a Command registers itself when constructed. + new CmdSleep(); + } + return Status::OK(); + } - // just for testing + // Testing only, enabled via command-line. class CapTrunc : public Command { public: CapTrunc() : Command( "captrunc" ) {} virtual bool slaveOk() const { return false; } virtual LockType locktype() const { return WRITE; } - virtual bool requiresAuth() { return true; } - // Only enabled via command line for testing + // No auth needed because it only works when enabled via command line. + virtual bool requiresAuth() { return false; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, - std::vector* out) { - ActionSet actions; - actions.addAction(ActionType::captrunc); - out->push_back(Privilege(parseNs(dbname, cmdObj), actions)); - } + std::vector* out) {} virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { string coll = cmdObj[ "captrunc" ].valuestrsafe(); uassert( 13416, "captrunc must specify a collection", !coll.empty() ); @@ -1799,24 +1813,27 @@ namespace mongo { nsd->cappedTruncateAfter( ns.c_str(), end, inc ); return true; } - } capTruncCmd; + }; + MONGO_INITIALIZER(RegisterCapTruncCmd)(InitializerContext* context) { + if (Command::testCommandsEnabled) { + // Leaked intentionally: a Command registers itself when constructed. + new CapTrunc(); + } + return Status::OK(); + } - // just for testing + // Testing-only, enabled via command line. class EmptyCapped : public Command { public: EmptyCapped() : Command( "emptycapped" ) {} virtual bool slaveOk() const { return false; } virtual LockType locktype() const { return WRITE; } - virtual bool requiresAuth() { return true; } virtual bool logTheOp() { return true; } - // Only enabled via command line for testing + // No auth needed because it only works when enabled via command line. + virtual bool requiresAuth() { return false; } virtual void addRequiredPrivileges(const std::string& dbname, const BSONObj& cmdObj, - std::vector* out) { - ActionSet actions; - actions.addAction(ActionType::emptycapped); - out->push_back(Privilege(parseNs(dbname, cmdObj), actions)); - } + std::vector* out) {} virtual bool run(const string& dbname , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { string coll = cmdObj[ "emptycapped" ].valuestrsafe(); uassert( 13428, "emptycapped must specify a collection", !coll.empty() ); @@ -1826,7 +1843,14 @@ namespace mongo { nsd->emptyCappedCollection( ns.c_str() ); return true; } - } emptyCappedCmd; + }; + MONGO_INITIALIZER(RegisterEmptyCappedCmd)(InitializerContext* context) { + if (Command::testCommandsEnabled) { + // Leaked intentionally: a Command registers itself when constructed. + new EmptyCapped(); + } + return Status::OK(); + } bool _execCommand(Command *c, const string& dbname, BSONObj& cmdObj, int queryOptions, BSONObjBuilder& result, bool fromRepl) { diff --git a/src/mongo/db/dbcommands_admin.cpp b/src/mongo/db/dbcommands_admin.cpp index c2ebc19ab80..f0201cd58e2 100644 --- a/src/mongo/db/dbcommands_admin.cpp +++ b/src/mongo/db/dbcommands_admin.cpp @@ -30,6 +30,8 @@ #include #include +#include "mongo/base/init.h" +#include "mongo/base/status.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_manager.h" @@ -90,7 +92,8 @@ namespace mongo { namespace dur { boost::filesystem::path getJournalDir(); } - + + // Testing-only, enabled via command line class JournalLatencyTestCmd : public Command { public: JournalLatencyTestCmd() : Command( "journalLatencyTest" ) {} @@ -99,7 +102,11 @@ namespace mongo { virtual LockType locktype() const { return NONE; } virtual bool adminOnly() const { return true; } virtual void help(stringstream& h) const { h << "test how long to write and fsync to a test file in the journal/ directory"; } - + // No auth needed because it only works when enabled via command line. + virtual bool requiresAuth() { return false; } + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector* out) {} bool run(const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { boost::filesystem::path p = dur::getJournalDir(); p /= "journalLatencyTest"; @@ -159,7 +166,14 @@ namespace mongo { return 1; } - } journalLatencyTestCmd; + }; + MONGO_INITIALIZER(RegisterJournalLatencyTestCmd)(InitializerContext* context) { + if (Command::testCommandsEnabled) { + // Leaked intentionally: a Command registers itself when constructed. + new JournalLatencyTestCmd(); + } + return Status::OK(); + } class ValidateCmd : public Command { public: diff --git a/src/mongo/db/repl/replset_commands.cpp b/src/mongo/db/repl/replset_commands.cpp index b21bba2de3b..af88f1b260e 100644 --- a/src/mongo/db/repl/replset_commands.cpp +++ b/src/mongo/db/repl/replset_commands.cpp @@ -16,6 +16,8 @@ #include "pch.h" +#include "mongo/base/init.h" +#include "mongo/base/status.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_manager.h" @@ -43,11 +45,17 @@ namespace mongo { bool replSetBlind = false; unsigned replSetForceInitialSyncFailure = 0; + // Testing only, enabled via command-line. class CmdReplSetTest : public ReplSetCommand { public: virtual void help( stringstream &help ) const { help << "Just for regression tests.\n"; } + // No auth needed because it only works when enabled via command line. + virtual bool requiresAuth() { return false; } + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector* out) {} CmdReplSetTest() : ReplSetCommand("replSetTest") { } virtual bool run(const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { log() << "replSet replSetTest command received: " << cmdObj.toString() << rsLog; @@ -76,7 +84,14 @@ namespace mongo { return false; } - } cmdReplSetTest; + }; + MONGO_INITIALIZER(RegisterReplSetTestCmd)(InitializerContext* context) { + if (Command::testCommandsEnabled) { + // Leaked intentionally: a Command registers itself when constructed. + new CmdReplSetTest(); + } + return Status::OK(); + } /** get rollback id. used to check if a rollback happened during some interval of time. as consumed, the rollback id is not in any particular order, it simply changes on each rollback. -- cgit v1.2.1