summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaria van Keulen <maria@mongodb.com>2018-01-10 17:25:17 -0500
committerMaria van Keulen <maria@mongodb.com>2018-02-12 19:40:12 -0500
commit200871c6f995ff1e51ca6565deecb01778b15d47 (patch)
treed39e98fd68fbc8a8bfde39019385b1f3b386b349
parente74bf273ef83cfbee332fe33079c0f640c71f7bb (diff)
downloadmongo-200871c6f995ff1e51ca6565deecb01778b15d47.tar.gz
SERVER-32205 Prohibit dropping the admin database at catalog level
(cherry picked from commit 72fc7cea722f952e3ad47c5470cb60ae2114097f)
-rw-r--r--jstests/multiVersion/set_feature_compatibility_version.js59
-rw-r--r--jstests/noPassthrough/feature_compatibility_version.js4
-rw-r--r--jstests/noPassthrough/system_indexes.js24
-rw-r--r--jstests/replsets/drop_oplog.js2
-rw-r--r--src/mongo/db/catalog/database_impl.cpp1
-rw-r--r--src/mongo/db/catalog/drop_database.cpp6
-rw-r--r--src/mongo/db/catalog/drop_database_test.cpp9
-rw-r--r--src/mongo/db/commands/dbcommands.cpp2
-rw-r--r--src/mongo/db/repl/apply_ops_test.cpp24
9 files changed, 59 insertions, 72 deletions
diff --git a/jstests/multiVersion/set_feature_compatibility_version.js b/jstests/multiVersion/set_feature_compatibility_version.js
index abf6043546d..e831c1e2736 100644
--- a/jstests/multiVersion/set_feature_compatibility_version.js
+++ b/jstests/multiVersion/set_feature_compatibility_version.js
@@ -30,25 +30,6 @@ TestData.skipCheckingUUIDsConsistentAcrossCluster = true;
};
let doStartupFailTests = function(withUUIDs, dbpath) {
- // Fail to start up if no admin database is present but other non-local databases are
- // present.
- if (withUUIDs) {
- setupMissingAdminDB(latest, dbpath);
- } else {
- setupMissingAdminDB(downgrade, dbpath);
- }
- conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, noCleanData: true});
- assert.eq(
- null,
- conn,
- "expected mongod to fail when data files are present and no admin database is found.");
- if (!withUUIDs) {
- conn =
- MongoRunner.runMongod({dbpath: dbpath, binVersion: downgrade, noCleanData: true});
- assert.neq(null, conn, "expected 3.4 to startup when the admin database is missing");
- MongoRunner.stopMongod(conn);
- }
-
// Fail to start up if no featureCompatibilityVersion document is present and non-local
// databases are present.
if (withUUIDs) {
@@ -93,20 +74,6 @@ TestData.skipCheckingUUIDsConsistentAcrossCluster = true;
return conn;
};
- let setupMissingAdminDB = function(version, dbpath) {
- conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: version});
- assert.neq(null,
- conn,
- "mongod was unable to start up with version=" + version + " and no data files");
- let testDB = conn.getDB("test");
- assert.commandWorked(testDB.createCollection("testcoll"));
- adminDB = conn.getDB("admin");
- assert.commandWorked(adminDB.runCommand({dropDatabase: 1}),
- "expected drop of admin database to be successful");
- MongoRunner.stopMongod(conn);
- return conn;
- };
-
//
// Standalone tests.
//
@@ -230,35 +197,11 @@ TestData.skipCheckingUUIDsConsistentAcrossCluster = true;
// Fail to start up if no featureCompatibilityVersion is present and no collections have UUIDs.
doStartupFailTests(/*withUUIDs*/ false, dbpath);
- // --repair can be used to restore a missing admin database and featureCompatibilityVersion
- // document if at least some collections have UUIDs.
- conn = setupMissingAdminDB(latest, dbpath);
- recoverMMapJournal(isMMAPv1, conn, dbpath);
- let returnCode = runMongoProgram("mongod", "--port", conn.port, "--repair", "--dbpath", dbpath);
- assert.eq(
- returnCode,
- 0,
- "expected mongod --repair to execute successfully when restoring a missing admin database.");
- conn = MongoRunner.runMongod({dbpath: dbpath, binVersion: latest, noCleanData: true});
- assert.neq(null,
- conn,
- "mongod was unable to start up with version=" + latest + " and existing data files");
- // featureCompatibilityVersion is 3.4 and targetVersion is 3.6 because the admin.system.version
- // collection was restored without a UUID.
- adminDB = conn.getDB("admin");
- assert.eq(adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).version, "3.4");
- assert.eq(adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}).targetVersion,
- "3.6");
- let adminInfos = adminDB.getCollectionInfos();
- assert(!adminInfos[0].info.uuid,
- "Expected collection with infos " + tojson(adminInfos) + " to not have a UUID.");
- MongoRunner.stopMongod(conn);
-
// --repair can be used to restore a missing featureCompatibilityVersion document to an
// existing admin database if at least some collections have UUIDs.
conn = setupMissingFCVDoc(latest, dbpath);
recoverMMapJournal(isMMAPv1, conn, dbpath);
- returnCode = runMongoProgram("mongod", "--port", conn.port, "--repair", "--dbpath", dbpath);
+ let returnCode = runMongoProgram("mongod", "--port", conn.port, "--repair", "--dbpath", dbpath);
assert.eq(
returnCode,
0,
diff --git a/jstests/noPassthrough/feature_compatibility_version.js b/jstests/noPassthrough/feature_compatibility_version.js
index 016c5d12e08..f3824a3a0b5 100644
--- a/jstests/noPassthrough/feature_compatibility_version.js
+++ b/jstests/noPassthrough/feature_compatibility_version.js
@@ -91,9 +91,5 @@
adminDB.system.version.insert({_id: "featureCompatibilityVersion", version: "3.6"}));
checkFCV(adminDB, "3.6");
- // Dropping the admin database changes the featureCompatibilityVersion server parameter to 3.4.
- adminDB.dropDatabase();
- checkFCVDocumentMissing(adminDB);
-
MongoRunner.stopMongod(conn);
}());
diff --git a/jstests/noPassthrough/system_indexes.js b/jstests/noPassthrough/system_indexes.js
index f95d7bf1a8d..3fa784e97da 100644
--- a/jstests/noPassthrough/system_indexes.js
+++ b/jstests/noPassthrough/system_indexes.js
@@ -47,10 +47,14 @@
// TEST: Destroying the admin.system.users index and restarting will recreate it, even if
// admin.system.roles does not exist
- db.dropDatabase();
- // Restore the featureCompatibilityVersion document since as of SERVER-29452, mongod fails to
- // startup without such a document.
- assert.commandWorked(db.runCommand({setFeatureCompatibilityVersion: "3.6"}));
+ // Use _mergeAuthzCollections to clear admin.system.users and admin.system.roles.
+ assert.commandWorked(db.adminCommand({
+ _mergeAuthzCollections: 1,
+ tempUsersCollection: 'admin.tempusers',
+ tempRolesCollection: 'admin.temproles',
+ db: "",
+ drop: true
+ }));
db.createUser({user: "user", pwd: "pwd", roles: []});
assert.commandWorked(db.system.users.dropIndexes());
MongoRunner.stopMongod(conn);
@@ -60,10 +64,14 @@
// TEST: Destroying the admin.system.roles index and restarting will recreate it, even if
// admin.system.users does not exist
- db.dropDatabase();
- // Restore the featureCompatibilityVersion document since as of SERVER-29452, mongod fails to
- // startup without such a document.
- assert.commandWorked(db.runCommand({setFeatureCompatibilityVersion: "3.6"}));
+ // Use _mergeAuthzCollections to clear admin.system.users and admin.system.roles.
+ assert.commandWorked(db.adminCommand({
+ _mergeAuthzCollections: 1,
+ tempUsersCollection: 'admin.tempusers',
+ tempRolesCollection: 'admin.temproles',
+ db: "",
+ drop: true
+ }));
db.createRole({role: "role", privileges: [], roles: []});
assert.commandWorked(db.system.roles.dropIndexes());
MongoRunner.stopMongod(conn);
diff --git a/jstests/replsets/drop_oplog.js b/jstests/replsets/drop_oplog.js
index df89ec255ff..8e2a7c2e1d2 100644
--- a/jstests/replsets/drop_oplog.js
+++ b/jstests/replsets/drop_oplog.js
@@ -22,7 +22,7 @@
let adminDB = master.getDB('admin');
dropOutput = adminDB.dropDatabase();
assert.eq(dropOutput.ok, 0);
- assert.eq(dropOutput.errmsg, "Cannot drop 'admin' database while replication is active");
+ assert.eq(dropOutput.errmsg, "Dropping the 'admin' database is prohibited.");
let renameOutput = localDB.oplog.rs.renameCollection("poison");
assert.eq(renameOutput.ok, 0);
diff --git a/src/mongo/db/catalog/database_impl.cpp b/src/mongo/db/catalog/database_impl.cpp
index dc044477718..d9d123fa167 100644
--- a/src/mongo/db/catalog/database_impl.cpp
+++ b/src/mongo/db/catalog/database_impl.cpp
@@ -856,6 +856,7 @@ void DatabaseImpl::dropDatabase(OperationContext* opCtx, Database* db) {
// Store the name so we have if for after the db object is deleted
const string name = db->name();
+
LOG(1) << "dropDatabase " << name;
invariant(opCtx->lockState()->isDbLockedForMode(name, MODE_X));
diff --git a/src/mongo/db/catalog/drop_database.cpp b/src/mongo/db/catalog/drop_database.cpp
index cea9b55f66b..25a4d9f4294 100644
--- a/src/mongo/db/catalog/drop_database.cpp
+++ b/src/mongo/db/catalog/drop_database.cpp
@@ -82,6 +82,12 @@ Status dropDatabase(OperationContext* opCtx, const std::string& dbName) {
uassert(ErrorCodes::IllegalOperation,
"Cannot drop a database in read-only mode",
!storageGlobalParams.readOnly);
+
+ // As of SERVER-32205, dropping the admin database is prohibited.
+ uassert(ErrorCodes::IllegalOperation,
+ str::stream() << "Dropping the '" << dbName << "' database is prohibited.",
+ dbName != NamespaceString::kAdminDb);
+
// TODO (Kal): OldClientContext legacy, needs to be removed
{
CurOp::get(opCtx)->ensureStarted();
diff --git a/src/mongo/db/catalog/drop_database_test.cpp b/src/mongo/db/catalog/drop_database_test.cpp
index f26a624d687..1d351be54d4 100644
--- a/src/mongo/db/catalog/drop_database_test.cpp
+++ b/src/mongo/db/catalog/drop_database_test.cpp
@@ -455,4 +455,13 @@ TEST_F(DropDatabaseTest,
ASSERT_FALSE(db->isDropPending(_opCtx.get()));
}
+TEST_F(DropDatabaseTest, DropDatabaseFailsToDropAdmin) {
+ NamespaceString adminNSS(NamespaceString::kAdminDb, "foo");
+ _createCollection(_opCtx.get(), adminNSS);
+ ASSERT_THROWS_CODE_AND_WHAT(dropDatabase(_opCtx.get(), adminNSS.db().toString()).ignore(),
+ AssertionException,
+ ErrorCodes::IllegalOperation,
+ "Dropping the 'admin' database is prohibited.");
+}
+
} // namespace
diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp
index 693bb58d5a0..9bd32266d0f 100644
--- a/src/mongo/db/commands/dbcommands.cpp
+++ b/src/mongo/db/commands/dbcommands.cpp
@@ -181,7 +181,7 @@ public:
if ((repl::getGlobalReplicationCoordinator()->getReplicationMode() !=
repl::ReplicationCoordinator::modeNone) &&
- ((dbname == NamespaceString::kLocalDb) || (dbname == NamespaceString::kAdminDb))) {
+ (dbname == NamespaceString::kLocalDb)) {
return appendCommandStatus(
result,
Status(ErrorCodes::IllegalOperation,
diff --git a/src/mongo/db/repl/apply_ops_test.cpp b/src/mongo/db/repl/apply_ops_test.cpp
index 2bb1a221f86..e43a3092978 100644
--- a/src/mongo/db/repl/apply_ops_test.cpp
+++ b/src/mongo/db/repl/apply_ops_test.cpp
@@ -306,6 +306,30 @@ TEST_F(ApplyOpsTest, ApplyOpsPropagatesOplogApplicationMode) {
stopCapturingLogMessages();
}
+TEST_F(ApplyOpsTest, ApplyOpsFailsToDropAdmin) {
+ auto opCtx = cc().makeOperationContext();
+ auto mode = OplogApplication::Mode::kApplyOpsCmd;
+
+ // Create a collection on the admin database.
+ NamespaceString nss("admin.foo");
+ CollectionOptions options;
+ options.uuid = UUID::gen();
+ ASSERT_OK(_storage->createCollection(opCtx.get(), nss, options));
+
+ auto dropDatabaseOp = BSON("op"
+ << "c"
+ << "ns"
+ << nss.getCommandNS().ns()
+ << "o"
+ << BSON("dropDatabase" << 1));
+
+ auto dropDatabaseCmdObj = BSON("applyOps" << BSON_ARRAY(dropDatabaseOp));
+ BSONObjBuilder resultBuilder;
+ auto status =
+ applyOps(opCtx.get(), nss.db().toString(), dropDatabaseCmdObj, mode, &resultBuilder);
+ ASSERT_EQUALS(ErrorCodes::UnknownError, status);
+}
+
} // namespace
} // namespace repl
} // namespace mongo