diff options
-rw-r--r-- | buildscripts/resmokeconfig/suites/replica_sets_legacy.yml | 1 | ||||
-rw-r--r-- | jstests/auth/lib/commands_lib.js | 15 | ||||
-rw-r--r-- | jstests/replsets/stepup.js | 53 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator.h | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl.cpp | 21 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_impl.h | 1 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_mock.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/repl/replication_coordinator_mock.h | 2 | ||||
-rw-r--r-- | src/mongo/db/repl/replset_commands.cpp | 33 |
9 files changed, 132 insertions, 0 deletions
diff --git a/buildscripts/resmokeconfig/suites/replica_sets_legacy.yml b/buildscripts/resmokeconfig/suites/replica_sets_legacy.yml index 0dd1bdaf1d6..beac15e6af8 100644 --- a/buildscripts/resmokeconfig/suites/replica_sets_legacy.yml +++ b/buildscripts/resmokeconfig/suites/replica_sets_legacy.yml @@ -16,6 +16,7 @@ selector: - jstests/replsets/read_majority_two_arbs.js # The combination of new bridges and PV0 can lead to an improper spanning tree in sync2.js. - jstests/replsets/sync2.js + - jstests/replsets/stepup.js executor: js_test: diff --git a/jstests/auth/lib/commands_lib.js b/jstests/auth/lib/commands_lib.js index 10fe4cd0216..d7aae4fb70d 100644 --- a/jstests/auth/lib/commands_lib.js +++ b/jstests/auth/lib/commands_lib.js @@ -2377,6 +2377,21 @@ var authCommandsLib = { ] }, { + testname: "replSetStepUp", + command: {replSetStepUp: "x"}, + skipSharded: true, + testcases: [ + { + runOnDb: adminDbName, + roles: roles_clusterManager, + privileges: [{resource: {cluster: true}, actions: ["replSetStateChange"]}], + expectFail: true + }, + {runOnDb: firstDbName, roles: {}}, + {runOnDb: secondDbName, roles: {}} + ] + }, + { testname: "replSetSyncFrom", command: {replSetSyncFrom: "x"}, skipSharded: true, diff --git a/jstests/replsets/stepup.js b/jstests/replsets/stepup.js new file mode 100644 index 00000000000..f772febfe50 --- /dev/null +++ b/jstests/replsets/stepup.js @@ -0,0 +1,53 @@ +// Tests the replSetStepUp command. + +load("jstests/replsets/rslib.js"); + +(function() { + + "use strict"; + var name = "stepup"; + var rst = new ReplSetTest({name: name, nodes: 2}); + + rst.startSet(); + // Initiate the replset in protocol version 0. + var conf = rst.getReplSetConfig(); + conf.protocolVersion = 0; + rst.initiate(conf); + rst.awaitReplication(); + + var primary = rst.getPrimary(); + var secondary = rst.getSecondary(); + var res = secondary.adminCommand({replSetStepUp: 1}); + assert.commandFailedWithCode(res, ErrorCodes.CommandNotSupported); + + // Upgrade protocol version + conf = rst.getReplSetConfigFromNode(); + conf.protocolVersion = 1; + conf.version++; + reconfig(rst, conf); + // Wait for the upgrade to finish. + assert.writeOK(primary.getDB("test").bar.insert({x: 1}, {writeConcern: {w: 2}})); + + // Step up the primary. Return OK because it's already the primary. + res = primary.adminCommand({replSetStepUp: 1}); + assert.commandWorked(res); + assert.eq(primary, rst.getPrimary()); + + // Step up the secondary, but it's not eligible to be primary. + // Enable fail point on secondary. + assert.commandWorked(secondary.getDB('admin').runCommand( + {configureFailPoint: 'rsSyncApplyStop', mode: 'alwaysOn'})); + + assert.writeOK(primary.getDB("test").bar.insert({x: 2}, {writeConcern: {w: 1}})); + res = secondary.adminCommand({replSetStepUp: 1}); + assert.commandFailedWithCode(res, ErrorCodes.NotMaster); + assert.commandWorked( + secondary.getDB('admin').runCommand({configureFailPoint: 'rsSyncApplyStop', mode: 'off'})); + + // Step up the secondary and succeed. + rst.awaitReplication(); + res = secondary.adminCommand({replSetStepUp: 1}); + assert.commandWorked(res); + assert.eq(secondary, rst.getPrimary()); + +})(); diff --git a/src/mongo/db/repl/replication_coordinator.h b/src/mongo/db/repl/replication_coordinator.h index 37c89b5c67f..47ace7b21be 100644 --- a/src/mongo/db/repl/replication_coordinator.h +++ b/src/mongo/db/repl/replication_coordinator.h @@ -785,6 +785,8 @@ public: virtual ReplSettings::IndexPrefetchConfig getIndexPrefetchConfig() const = 0; virtual void setIndexPrefetchConfig(const ReplSettings::IndexPrefetchConfig cfg) = 0; + virtual Status stepUpIfEligible() = 0; + protected: ReplicationCoordinator(); }; diff --git a/src/mongo/db/repl/replication_coordinator_impl.cpp b/src/mongo/db/repl/replication_coordinator_impl.cpp index 5ffd00cef2b..215e9667866 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.cpp +++ b/src/mongo/db/repl/replication_coordinator_impl.cpp @@ -3536,6 +3536,27 @@ CallbackFn ReplicationCoordinatorImpl::_wrapAsCallbackFn(const stdx::function<vo }; } +Status ReplicationCoordinatorImpl::stepUpIfEligible() { + if (!isV1ElectionProtocol()) { + return Status(ErrorCodes::CommandNotSupported, + "Step-up command is only supported by Protocol Version 1"); + } + + _startElectSelfIfEligibleV1(false); + EventHandle finishEvent; + { + LockGuard lk(_mutex); + finishEvent = _electionFinishedEvent; + } + if (finishEvent.isValid()) { + _replExecutor.waitForEvent(finishEvent); + } + auto state = getMemberState(); + if (state.primary()) { + return Status::OK(); + } + return Status(ErrorCodes::CommandFailed, "Election failed."); +} bool ReplicationCoordinatorImpl::getInitialSyncRequestedFlag() const { stdx::lock_guard<stdx::mutex> lock(_initialSyncMutex); diff --git a/src/mongo/db/repl/replication_coordinator_impl.h b/src/mongo/db/repl/replication_coordinator_impl.h index 1e8b369ff91..cacf60a96b7 100644 --- a/src/mongo/db/repl/replication_coordinator_impl.h +++ b/src/mongo/db/repl/replication_coordinator_impl.h @@ -334,6 +334,7 @@ public: virtual ReplSettings::IndexPrefetchConfig getIndexPrefetchConfig() const override; virtual void setIndexPrefetchConfig(const ReplSettings::IndexPrefetchConfig cfg) override; + virtual Status stepUpIfEligible() override; // ================== Test support API =================== diff --git a/src/mongo/db/repl/replication_coordinator_mock.cpp b/src/mongo/db/repl/replication_coordinator_mock.cpp index 91893d37325..4e1cdff5434 100644 --- a/src/mongo/db/repl/replication_coordinator_mock.cpp +++ b/src/mongo/db/repl/replication_coordinator_mock.cpp @@ -449,5 +449,9 @@ ReplSettings::IndexPrefetchConfig ReplicationCoordinatorMock::getIndexPrefetchCo void ReplicationCoordinatorMock::setIndexPrefetchConfig( const ReplSettings::IndexPrefetchConfig cfg) {} +Status ReplicationCoordinatorMock::stepUpIfEligible() { + return Status::OK(); +} + } // namespace repl } // namespace mongo diff --git a/src/mongo/db/repl/replication_coordinator_mock.h b/src/mongo/db/repl/replication_coordinator_mock.h index ec76a9677ac..67d8fd0ed27 100644 --- a/src/mongo/db/repl/replication_coordinator_mock.h +++ b/src/mongo/db/repl/replication_coordinator_mock.h @@ -256,6 +256,8 @@ public: virtual ReplSettings::IndexPrefetchConfig getIndexPrefetchConfig() const override; virtual void setIndexPrefetchConfig(const ReplSettings::IndexPrefetchConfig cfg) override; + virtual Status stepUpIfEligible() override; + private: AtomicUInt64 _snapshotNameGenerator; const ReplSettings _settings; diff --git a/src/mongo/db/repl/replset_commands.cpp b/src/mongo/db/repl/replset_commands.cpp index 12ace8dc728..9130052de75 100644 --- a/src/mongo/db/repl/replset_commands.cpp +++ b/src/mongo/db/repl/replset_commands.cpp @@ -893,5 +893,38 @@ private: } } cmdReplSetElect; +class CmdReplSetStepUp : public ReplSetCommand { +public: + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { + ActionSet actions; + actions.addAction(ActionType::replSetStateChange); + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(), actions)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + return Status::OK(); + } + + CmdReplSetStepUp() : ReplSetCommand("replSetStepUp") {} + +private: + virtual bool run(OperationContext* txn, + const string&, + BSONObj& cmdObj, + int, + string& errmsg, + BSONObjBuilder& result) { + Status status = getGlobalReplicationCoordinator()->checkReplEnabledForCommand(&result); + if (!status.isOK()) + return appendCommandStatus(result, status); + + status = getGlobalReplicationCoordinator()->stepUpIfEligible(); + + return appendCommandStatus(result, status); + } +} cmdReplSetStepUp; + } // namespace repl } // namespace mongo |