summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buildscripts/resmokeconfig/suites/replica_sets_legacy.yml1
-rw-r--r--jstests/auth/lib/commands_lib.js15
-rw-r--r--jstests/replsets/stepup.js53
-rw-r--r--src/mongo/db/repl/replication_coordinator.h2
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.cpp21
-rw-r--r--src/mongo/db/repl/replication_coordinator_impl.h1
-rw-r--r--src/mongo/db/repl/replication_coordinator_mock.cpp4
-rw-r--r--src/mongo/db/repl/replication_coordinator_mock.h2
-rw-r--r--src/mongo/db/repl/replset_commands.cpp33
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