summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBlake Oler <blake.oler@mongodb.com>2018-02-21 13:43:24 -0500
committerBlake Oler <blake.oler@mongodb.com>2018-02-26 12:41:07 -0500
commitc88d4b73a63011f624cc1cf1cdd7692943d11ffa (patch)
treec320de4c89ea3b8f45bdbb697b3c7a244957f561
parent2677c5d70bc2ddcf10b3ab1a3df5ad6f1d8abf7f (diff)
downloadmongo-c88d4b73a63011f624cc1cf1cdd7692943d11ffa.tar.gz
SERVER-33196 add 'forTest' flag to movePrimary, and if it's set, make _configsvrMovePrimary call movePrimary on the primary shard
-rw-r--r--jstests/sharding/move_primary_basic.js3
-rw-r--r--jstests/sharding/move_primary_with_test_flag.js51
-rw-r--r--src/mongo/db/s/config/configsvr_move_primary_command.cpp38
-rw-r--r--src/mongo/db/s/move_primary_command.cpp41
-rw-r--r--src/mongo/s/commands/cluster_move_primary_cmd.cpp1
-rw-r--r--src/mongo/s/request_types/move_primary.idl22
6 files changed, 143 insertions, 13 deletions
diff --git a/jstests/sharding/move_primary_basic.js b/jstests/sharding/move_primary_basic.js
index e2e609fc866..3a54d51be06 100644
--- a/jstests/sharding/move_primary_basic.js
+++ b/jstests/sharding/move_primary_basic.js
@@ -18,9 +18,6 @@
st.ensurePrimaryShard(kDbName, shard0);
assert.eq(shard0, mongos.getDB('config').databases.findOne({_id: kDbName}).primary);
- // Can run on shards.
- assert.commandWorked(st.d0.getDB('admin').runCommand({_movePrimary: kDbName, to: shard1}));
-
// Can run only against the admin database.
assert.commandFailedWithCode(
mongos.getDB('test').runCommand({movePrimary: kDbName, to: shard0}),
diff --git a/jstests/sharding/move_primary_with_test_flag.js b/jstests/sharding/move_primary_with_test_flag.js
new file mode 100644
index 00000000000..e02b714de50
--- /dev/null
+++ b/jstests/sharding/move_primary_with_test_flag.js
@@ -0,0 +1,51 @@
+//
+// Tests for movePrimary with test flag.
+//
+
+(function() {
+ 'use strict';
+
+ var st = new ShardingTest({mongos: 1, shards: 2});
+
+ var mongos = st.s0;
+
+ var kDbName = 'db';
+
+ var shard0 = st.shard0.shardName;
+ var shard1 = st.shard1.shardName;
+
+ assert.commandWorked(mongos.adminCommand({enableSharding: kDbName}));
+ st.ensurePrimaryShard(kDbName, shard0);
+ assert.eq(shard0, mongos.getDB('config').databases.findOne({_id: kDbName}).primary);
+
+ // Can run only against the admin database.
+ assert.commandFailedWithCode(
+ mongos.getDB('test').runCommand({movePrimary: kDbName, to: shard0, forTest: true}),
+ ErrorCodes.Unauthorized);
+
+ // Can't movePrimary for 'config' database.
+ assert.commandFailed(mongos.adminCommand({movePrimary: 'config', to: shard0, forTest: true}));
+
+ // Can't movePrimary for 'local' database.
+ assert.commandFailed(mongos.adminCommand({movePrimary: 'local', to: shard0, forTest: true}));
+
+ // Can't movePrimary for 'admin' database.
+ assert.commandFailed(mongos.adminCommand({movePrimary: 'admin', to: shard0, forTest: true}));
+
+ // Can't movePrimary for invalid db name.
+ assert.commandFailed(mongos.adminCommand({movePrimary: 'a.b', to: shard0, forTest: true}));
+ assert.commandFailed(mongos.adminCommand({movePrimary: '', to: shard0, forTest: true}));
+
+ // Fail if 'to' shard is empty.
+ assert.commandFailed(mongos.adminCommand({movePrimary: kDbName, to: '', forTest: true}));
+ assert.commandFailed(mongos.adminCommand({movePrimary: kDbName, forTest: true}));
+
+ // Succeed if 'to' shard is already the primary shard for the db.
+ assert.commandWorked(mongos.adminCommand({movePrimary: kDbName, to: shard1, forTest: true}));
+ // The following line will be uncommented when the underlying fcv 4.0 movePrimary logic is
+ // complete.
+ // assert.eq(shard1, mongos.getDB('config').databases.findOne({_id: kDbName}).primary);
+
+ st.stop();
+
+})();
diff --git a/src/mongo/db/s/config/configsvr_move_primary_command.cpp b/src/mongo/db/s/config/configsvr_move_primary_command.cpp
index 4389584d922..82fd5898f8f 100644
--- a/src/mongo/db/s/config/configsvr_move_primary_command.cpp
+++ b/src/mongo/db/s/config/configsvr_move_primary_command.cpp
@@ -134,6 +134,15 @@ public:
<< cmdObj,
opCtx->getWriteConcern().wMode == WriteConcernOptions::kMajority);
+ const std::string to = movePrimaryRequest.getTo().toString();
+
+ if (to.empty()) {
+ return CommandHelpers::appendCommandStatus(
+ result,
+ {ErrorCodes::InvalidOptions,
+ str::stream() << "you have to specify where you want to move it"});
+ }
+
auto const catalogClient = Grid::get(opCtx)->catalogClient();
auto const catalogCache = Grid::get(opCtx)->catalogCache();
auto const catalogManager = ShardingCatalogManager::get(opCtx);
@@ -152,16 +161,29 @@ public:
opCtx, dbname, repl::ReadConcernLevel::kLocalReadConcern))
.value;
- const std::string to = movePrimaryRequest.getTo().toString();
+ const auto fromShard = uassertStatusOK(shardRegistry->getShard(opCtx, dbType.getPrimary()));
- if (to.empty()) {
- return CommandHelpers::appendCommandStatus(
- result,
- {ErrorCodes::InvalidOptions,
- str::stream() << "you have to specify where you want to move it"});
- }
+ // fcv 4.0 logic for movePrimary (being tested under the 'forTest' flag while in
+ // development).
+ if (movePrimaryRequest.getForTest()) {
+ const NamespaceString nss(dbname);
- const auto fromShard = uassertStatusOK(shardRegistry->getShard(opCtx, dbType.getPrimary()));
+ ShardMovePrimary shardMovePrimaryRequest;
+ shardMovePrimaryRequest.set_movePrimary(nss);
+ shardMovePrimaryRequest.setTo(movePrimaryRequest.getTo());
+
+ auto cmdResponse = uassertStatusOK(fromShard->runCommandWithFixedRetryAttempts(
+ opCtx,
+ ReadPreferenceSetting(ReadPreference::PrimaryOnly),
+ "admin",
+ CommandHelpers::appendMajorityWriteConcern(CommandHelpers::appendPassthroughFields(
+ cmdObj, shardMovePrimaryRequest.toBSON())),
+ Shard::RetryPolicy::kIdempotent));
+
+ CommandHelpers::filterCommandReplyForPassthrough(cmdResponse.response, &result);
+
+ return true;
+ }
const auto toShard = [&]() {
auto toShardStatus = shardRegistry->getShard(opCtx, to);
diff --git a/src/mongo/db/s/move_primary_command.cpp b/src/mongo/db/s/move_primary_command.cpp
index 58ccf871748..6375c3e9bf4 100644
--- a/src/mongo/db/s/move_primary_command.cpp
+++ b/src/mongo/db/s/move_primary_command.cpp
@@ -32,6 +32,7 @@
#include "mongo/db/auth/authorization_session.h"
#include "mongo/db/commands.h"
+#include "mongo/s/request_types/move_primary_gen.h"
#include "mongo/util/log.h"
namespace mongo {
@@ -67,8 +68,16 @@ public:
return Status::OK();
}
+ virtual std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const {
+ const auto nsElt = cmdObj.firstElement();
+ uassert(ErrorCodes::InvalidNamespace,
+ "'movePrimary' must be of type String",
+ nsElt.type() == BSONType::String);
+ return nsElt.str();
+ }
+
bool run(OperationContext* opCtx,
- const std::string& dbname,
+ const std::string& dbname_unused,
const BSONObj& cmdObj,
BSONObjBuilder& result) override {
if (serverGlobalParams.clusterRole != ClusterRole::ShardServer) {
@@ -78,6 +87,36 @@ public:
"_movePrimary can only be run on shard servers"));
}
+ auto movePrimaryRequest = MovePrimary::parse(IDLParserErrorContext("_movePrimary"), cmdObj);
+ const auto dbname = parseNs("", cmdObj);
+
+ uassert(
+ ErrorCodes::InvalidNamespace,
+ str::stream() << "invalid db name specified: " << dbname,
+ NamespaceString::validDBName(dbname, NamespaceString::DollarInDbNameBehavior::Allow));
+
+ if (dbname == NamespaceString::kAdminDb || dbname == NamespaceString::kConfigDb ||
+ dbname == NamespaceString::kLocalDb) {
+ return CommandHelpers::appendCommandStatus(
+ result,
+ {ErrorCodes::InvalidOptions,
+ str::stream() << "Can't move primary for " << dbname << " database"});
+ }
+
+ uassert(ErrorCodes::InvalidOptions,
+ str::stream() << "_movePrimary must be called with majority writeConcern, got "
+ << cmdObj,
+ opCtx->getWriteConcern().wMode == WriteConcernOptions::kMajority);
+
+ const std::string to = movePrimaryRequest.getTo().toString();
+
+ if (to.empty()) {
+ return CommandHelpers::appendCommandStatus(
+ result,
+ {ErrorCodes::InvalidOptions,
+ str::stream() << "you have to specify where you want to move it"});
+ }
+
return true;
}
diff --git a/src/mongo/s/commands/cluster_move_primary_cmd.cpp b/src/mongo/s/commands/cluster_move_primary_cmd.cpp
index 7dcc1a6f101..0d21748b29a 100644
--- a/src/mongo/s/commands/cluster_move_primary_cmd.cpp
+++ b/src/mongo/s/commands/cluster_move_primary_cmd.cpp
@@ -105,6 +105,7 @@ public:
ConfigsvrMovePrimary configMovePrimaryRequest;
configMovePrimaryRequest.set_configsvrMovePrimary(nss);
configMovePrimaryRequest.setTo(movePrimaryRequest.getTo());
+ configMovePrimaryRequest.setForTest(movePrimaryRequest.getForTest());
// Invalidate the routing table cache entry for this database so that we reload the
// collection the next time it's accessed, even if we receive a failure, e.g. NetworkError.
diff --git a/src/mongo/s/request_types/move_primary.idl b/src/mongo/s/request_types/move_primary.idl
index d4f79660e60..2e944cbb8ec 100644
--- a/src/mongo/s/request_types/move_primary.idl
+++ b/src/mongo/s/request_types/move_primary.idl
@@ -48,6 +48,10 @@ structs:
to:
type: string
description: "The shard serving as the destination for un-sharded collections."
+ forTest:
+ type: bool
+ description: "The flag indicating whether the fcv 4.0 logic for movePrimary should be used."
+ default: false
ConfigsvrMovePrimary:
description: "The internal movePrimary command on the config server"
@@ -58,4 +62,20 @@ structs:
description: "The namespace of the database whose primary shard is to be reassigned."
to:
type: string
- description: "The shard serving as the destination for un-sharded collections." \ No newline at end of file
+ description: "The shard serving as the destination for un-sharded collections."
+ forTest:
+ type: bool
+ description: "The flag indicating whether the fcv 4.0 logic for movePrimary should be used."
+ default: false
+
+ ShardMovePrimary:
+ description: "The internal movePrimary command on a primary shard"
+ strict: false
+ fields:
+ _movePrimary:
+ type: namespacestring
+ description: "The namespace of the database whose primary shard is to be reassigned."
+ to:
+ type: string
+ description: "The shard serving as the destination for un-sharded collections."
+ \ No newline at end of file