summaryrefslogtreecommitdiff
path: root/src/mongo/shell/replsettest.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/shell/replsettest.js')
-rw-r--r--src/mongo/shell/replsettest.js74
1 files changed, 70 insertions, 4 deletions
diff --git a/src/mongo/shell/replsettest.js b/src/mongo/shell/replsettest.js
index 64e9ca7a770..a2cc63516e6 100644
--- a/src/mongo/shell/replsettest.js
+++ b/src/mongo/shell/replsettest.js
@@ -195,6 +195,40 @@ var ReplSetTest = function(opts) {
}
/**
+ * Wrap a function so it can accept a node id or connection as its first argument. The argument
+ * is converted to a connection.
+ */
+ function _nodeParamToConn(wrapped) {
+ return function(node, ...wrappedArgs) {
+ if (node.getDB) {
+ return wrapped.call(this, node, ...wrappedArgs);
+ }
+
+ assert(self.nodes.hasOwnProperty(node), `${node} not found in self.nodes`);
+ return wrapped.call(this, self.nodes[node], ...wrappedArgs);
+ };
+ }
+
+ /**
+ * Wrap a function so it accepts a single node or list of them as its first argument. The
+ * function is called once per node provided.
+ */
+ function _nodeParamToSingleNode(wrapped) {
+ return function(node, ...wrappedArgs) {
+ if (node.hasOwnProperty('length')) {
+ let returnValueList = [];
+ for (let i = 0; i < node.length; i++) {
+ returnValueList.push(wrapped.call(this, node[i], ...wrappedArgs));
+ }
+
+ return returnValueList;
+ }
+
+ return wrapped.call(this, node, ...wrappedArgs);
+ };
+ }
+
+ /**
* Wait for a rs indicator to go to a particular state or states.
*
* @param node is a single node or list of nodes, by id or conn
@@ -1167,10 +1201,11 @@ var ReplSetTest = function(opts) {
* Modifies the election timeout to be 24 hours so that no unplanned elections happen. Then
* runs replSetInitiate on the replica set with the new config.
*/
- this.initiateWithHighElectionTimeout = function(opts = {}) {
- let cfg = this.getReplSetConfig();
- cfg.settings = Object.assign(opts, {"electionTimeoutMillis": 24 * 60 * 60 * 1000});
- this.initiate(cfg);
+ this.initiateWithHighElectionTimeout = function(config) {
+ config = config || this.getReplSetConfig();
+ config.settings = config.settings || {};
+ config.settings["electionTimeoutMillis"] = ReplSetTest.kForeverMillis;
+ this.initiate(config);
};
/**
@@ -2505,6 +2540,31 @@ var ReplSetTest = function(opts) {
return started;
};
+ /**
+ * Step down and freeze a particular node or nodes.
+ *
+ * @param node is a single node or list of nodes, by id or conn
+ */
+ this.freeze = _nodeParamToSingleNode(_nodeParamToConn(function(node) {
+ assert.soon(() => {
+ try {
+ // Ensure node is not primary. Ignore errors, probably means it's already secondary.
+ node.adminCommand({replSetStepDown: ReplSetTest.kForeverSecs, force: true});
+ // Prevent node from running election. Fails if it already started an election.
+ assert.commandWorked(node.adminCommand({replSetFreeze: ReplSetTest.kForeverSecs}));
+ return true;
+ } catch (e) {
+ if (isNetworkError(e) || e.code === ErrorCodes.NotSecondary ||
+ e.code === ErrorCodes.NotYetInitialized) {
+ jsTestLog(`Failed to freeze node ${node.host}: ${e}`);
+ return false;
+ }
+
+ throw e;
+ }
+ }, `Failed to run replSetFreeze cmd on ${node.host}`);
+ }));
+
this.stopMaster = function(signal, opts) {
var master = this.getPrimary();
var master_id = this.getNodeId(master);
@@ -2810,6 +2870,12 @@ var ReplSetTest = function(opts) {
ReplSetTest.kDefaultTimeoutMS = 10 * 60 * 1000;
/**
+ * Global default number that's effectively infinite.
+ */
+ReplSetTest.kForeverSecs = 24 * 60 * 60;
+ReplSetTest.kForeverMillis = ReplSetTest.kForeverSecs * 1000;
+
+/**
* Set of states that the replica set can be in. Used for the wait functions.
*/
ReplSetTest.State = {