summaryrefslogtreecommitdiff
path: root/src/mongo/shell
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-11 15:07:35 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-11 15:07:35 -0300
commit4cb8841196d0625dfa3825aa326f071cd27c7b8b (patch)
tree1682a647d4463397c119183369ae6f750d5fdcff /src/mongo/shell
parentaa03c6362cbaa767638e6eed9b031d86dd2643d1 (diff)
parent8f0827553e09872941945a093b647a4211a9db7f (diff)
Update upstream source from tag 'upstream/6.0.0'master
Update to upstream version '6.0.0' with Debian dir 5604a80ec1c96ca76f25f40d78e6ef855abec322
Diffstat (limited to 'src/mongo/shell')
-rw-r--r--src/mongo/shell/SConscript1
-rw-r--r--src/mongo/shell/assert.js11
-rw-r--r--src/mongo/shell/check_log.js105
-rw-r--r--src/mongo/shell/data_consistency_checker.js22
-rw-r--r--src/mongo/shell/db.js51
-rw-r--r--src/mongo/shell/encrypted_dbclient_base.cpp77
-rw-r--r--src/mongo/shell/encrypted_dbclient_base.h60
-rw-r--r--src/mongo/shell/keyvault.js71
-rw-r--r--src/mongo/shell/linenoise.cpp5
-rw-r--r--src/mongo/shell/mongo_main.cpp10
-rw-r--r--src/mongo/shell/query.js8
-rw-r--r--src/mongo/shell/replsettest.js53
-rw-r--r--src/mongo/shell/servers.js39
-rw-r--r--src/mongo/shell/shardingtest.js994
-rw-r--r--src/mongo/shell/shell_utils.cpp22
-rw-r--r--src/mongo/shell/types.js30
-rw-r--r--src/mongo/shell/utils.js59
-rw-r--r--src/mongo/shell/utils_sh.js141
18 files changed, 708 insertions, 1051 deletions
diff --git a/src/mongo/shell/SConscript b/src/mongo/shell/SConscript
index 3b742237bc6..d8f54958a73 100644
--- a/src/mongo/shell/SConscript
+++ b/src/mongo/shell/SConscript
@@ -203,7 +203,6 @@ if get_option('ssl') == 'on':
"fle_shell_options.idl",
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/bson/bson_validate',
'$BUILD_DIR/mongo/client/clientdriver_minimal',
'$BUILD_DIR/mongo/crypto/aead_encryption',
'$BUILD_DIR/mongo/crypto/encrypted_field_config',
diff --git a/src/mongo/shell/assert.js b/src/mongo/shell/assert.js
index 6579443ae2e..ff168bd865d 100644
--- a/src/mongo/shell/assert.js
+++ b/src/mongo/shell/assert.js
@@ -110,8 +110,7 @@ assert = (function() {
doassert("msg function cannot expect any parameters.");
}
} else if (typeof msg !== "string" && typeof msg !== "object") {
- doassert("msg parameter must be a string, function or object. Found type: " +
- typeof (msg));
+ doassert("msg parameter must be a string, function or object.");
}
if (msg && assert._debug) {
@@ -842,12 +841,10 @@ assert = (function() {
assert.commandWorkedOrFailedWithCode = function commandWorkedOrFailedWithCode(
res, errorCodeSet, msg) {
- try {
- // First check if the command worked.
- return assert.commandWorked(res, msg);
- } catch (e) {
- // If the command did not work, assert it failed with one of the specified codes.
+ if (!res.ok) {
return assert.commandFailedWithCode(res, errorCodeSet, msg);
+ } else {
+ return assert.commandWorked(res, msg);
}
};
diff --git a/src/mongo/shell/check_log.js b/src/mongo/shell/check_log.js
index e31dd863519..fc74d871cc1 100644
--- a/src/mongo/shell/check_log.js
+++ b/src/mongo/shell/check_log.js
@@ -30,32 +30,6 @@ checkLog = (function() {
* is found in the logs. Note: this function does not throw an exception, so the return
* value should not be ignored.
*/
- const getLogMessage = function(conn, msg) {
- const logMessages = getGlobalLog(conn);
- if (logMessages === null) {
- return null;
- }
- if (msg instanceof RegExp) {
- for (let logMsg of logMessages) {
- if (logMsg.search(msg) != -1) {
- return logMsg;
- }
- }
- } else {
- for (let logMsg of logMessages) {
- if (logMsg.includes(msg)) {
- return logMsg;
- }
- }
- }
- return null;
- };
-
- /*
- * Calls the 'getLog' function on the provided connection 'conn' to see if the provided msg
- * is found in the logs. Note: this function does not throw an exception, so the return
- * value should not be ignored.
- */
const checkContainsOnce = function(conn, msg) {
const logMessages = getGlobalLog(conn);
if (logMessages === null) {
@@ -122,9 +96,26 @@ checkLog = (function() {
return actual === expected;
},
context = null) {
- const messages = getFilteredLogMessages(conn, id, attrsDict, severity, isRelaxed, context);
+ const logMessages = getGlobalLog(conn);
+ if (logMessages === null) {
+ return false;
+ }
+
+ let count = 0;
+ for (let logMsg of logMessages) {
+ let obj;
+ try {
+ obj = JSON.parse(logMsg);
+ } catch (ex) {
+ print('checkLog.checkContainsOnce: JsonJSON.parse() failed: ' + tojson(ex) + ': ' +
+ logMsg);
+ throw ex;
+ }
- const count = messages.length;
+ if (_compareLogs(obj, id, severity, context, attrsDict, isRelaxed)) {
+ count++;
+ }
+ }
return comparator(count, expectedCount);
};
@@ -165,36 +156,6 @@ checkLog = (function() {
};
/*
- * See checkContainsWithCountJson comment.
- */
- const getFilteredLogMessages = function(
- conn, id, attrsDict, severity = null, isRelaxed = false, context = null) {
- const logMessages = getGlobalLog(conn);
- if (logMessages === null) {
- return false;
- }
-
- let messages = [];
-
- for (let logMsg of logMessages) {
- let obj;
- try {
- obj = JSON.parse(logMsg);
- } catch (ex) {
- print('checkLog.checkContainsOnce: JsonJSON.parse() failed: ' + tojson(ex) + ': ' +
- logMsg);
- throw ex;
- }
-
- if (_compareLogs(obj, id, severity, context, attrsDict, isRelaxed)) {
- messages.push(obj);
- }
- }
-
- return messages;
- };
-
- /*
* Calls the 'getLog' function at regular intervals on the provided connection 'conn' until
* the provided 'msg' is found in the logs, or it times out. Throws an exception on timeout.
*/
@@ -210,29 +171,6 @@ checkLog = (function() {
{runHangAnalyzer: false});
};
- /*
- * Calls the 'getLog' function at regular intervals on the provided connection 'conn' until
- * the provided 'msg' is found in the logs and returned, or it times out. Throws an exception on
- * timeout.
- */
- let containsLog = function(conn, msg, timeoutMillis = 5 * 60 * 1000, retryIntervalMS = 300) {
- // Don't run the hang analyzer because we don't expect contains() to always succeed.
- let logMsg = null;
- assert.soon(
- function() {
- logMsg = getLogMessage(conn, msg);
- if (logMsg) {
- return true;
- }
- return false;
- },
- 'Could not find log entries containing the following message: ' + msg,
- timeoutMillis,
- retryIntervalMS,
- {runHangAnalyzer: false});
- return logMsg;
- };
-
let containsJson = function(conn, id, attrsDict, timeoutMillis = 5 * 60 * 1000) {
// Don't run the hang analyzer because we don't expect contains() to always succeed.
assert.soon(
@@ -472,21 +410,18 @@ checkLog = (function() {
return {
getGlobalLog: getGlobalLog,
- getLogMessage: getLogMessage,
checkContainsOnce: checkContainsOnce,
checkContainsOnceJson: checkContainsOnceJson,
checkContainsWithCountJson: checkContainsWithCountJson,
checkContainsWithAtLeastCountJson: checkContainsWithAtLeastCountJson,
checkContainsOnceJsonStringMatch: checkContainsOnceJsonStringMatch,
contains: contains,
- containsLog: containsLog,
containsJson: containsJson,
containsRelaxedJson: containsRelaxedJson,
containsWithCount: containsWithCount,
containsWithAtLeastCount: containsWithAtLeastCount,
formatAsLogLine: formatAsLogLine,
- formatAsJsonLogLine: formatAsJsonLogLine,
- getFilteredLogMessages: getFilteredLogMessages,
+ formatAsJsonLogLine: formatAsJsonLogLine
};
})();
})();
diff --git a/src/mongo/shell/data_consistency_checker.js b/src/mongo/shell/data_consistency_checker.js
index b3303c76857..3a1621b11de 100644
--- a/src/mongo/shell/data_consistency_checker.js
+++ b/src/mongo/shell/data_consistency_checker.js
@@ -370,28 +370,6 @@ var {DataConsistencyChecker} = (function() {
delete syncingInfo.idIndex.ns;
}
- // If the servers are using encryption and they specify an encryption option
- // in versions <7.2 this is stored on the primary but not the secondary.
- // This is not an actual failure since the data is correct on all nodes. We
- // can safely ignore this element in the configString.
- const encryptionRegex = /encryption=\(?[^)]*\),?/;
-
- if (sourceInfo.options && sourceInfo.options.storageEngine &&
- sourceInfo.options.storageEngine.wiredTiger &&
- sourceInfo.options.storageEngine.wiredTiger.configString) {
- sourceInfo.options.storageEngine.wiredTiger.configString =
- sourceInfo.options.storageEngine.wiredTiger.configString.replace(
- encryptionRegex, "");
- }
-
- if (syncingInfo.options && syncingInfo.options.storageEngine &&
- syncingInfo.options.storageEngine.wiredTiger &&
- syncingInfo.options.storageEngine.wiredTiger.configString) {
- syncingInfo.options.storageEngine.wiredTiger.configString =
- syncingInfo.options.storageEngine.wiredTiger.configString.replace(
- encryptionRegex, "");
- }
-
if (!bsonBinaryEqual(syncingInfo, sourceInfo)) {
prettyPrint(
`the two nodes have different attributes for the collection or view ${
diff --git a/src/mongo/shell/db.js b/src/mongo/shell/db.js
index 2364460d62a..d3800871af1 100644
--- a/src/mongo/shell/db.js
+++ b/src/mongo/shell/db.js
@@ -1745,6 +1745,57 @@ DB.prototype.watch = function(pipeline, options) {
return this._runAggregate({aggregate: 1, pipeline: pipeline}, aggOptions);
};
+DB.prototype.getFreeMonitoringStatus = function() {
+ 'use strict';
+ return assert.commandWorked(this.adminCommand({getFreeMonitoringStatus: 1}));
+};
+
+DB.prototype.enableFreeMonitoring = function() {
+ 'use strict';
+ let reply, isPrimary;
+ if (this.getMongo().getApiParameters().apiVersion) {
+ reply = this.hello();
+ isPrimary = reply.isWritablePrimary;
+ } else {
+ reply = this.isMaster();
+ isPrimary = reply.ismaster;
+ }
+
+ if (!isPrimary) {
+ print("ERROR: db.enableFreeMonitoring() may only be run on a primary");
+ return;
+ }
+
+ assert.commandWorked(this.adminCommand({setFreeMonitoring: 1, action: 'enable'}));
+
+ const cmd = this.adminCommand({getFreeMonitoringStatus: 1});
+ if (!cmd.ok && (cmd.code == ErrorCode.Unauthorized)) {
+ // Edge case: It's technically possible that a user can change free-mon state,
+ // but is not allowed to inspect it.
+ print("Successfully initiated free monitoring, but unable to determine status " +
+ "as you lack the 'checkFreeMonitoringStatus' privilege.");
+ return;
+ }
+ assert.commandWorked(cmd);
+
+ if (cmd.state !== 'enabled') {
+ const url = this.adminCommand({'getParameter': 1, 'cloudFreeMonitoringEndpointURL': 1})
+ .cloudFreeMonitoringEndpointURL;
+
+ print("Unable to get immediate response from the Cloud Monitoring service. We will" +
+ "continue to retry in the background. Please check your firewall " +
+ "settings to ensure that mongod can communicate with \"" + url + "\"");
+ return;
+ }
+
+ print(tojson(cmd));
+};
+
+DB.prototype.disableFreeMonitoring = function() {
+ 'use strict';
+ assert.commandWorked(this.adminCommand({setFreeMonitoring: 1, action: 'disable'}));
+};
+
// Writing `this.hasOwnProperty` would cause DB.prototype.getCollection() to be called since the
// DB's getProperty() handler in C++ takes precedence when a property isn't defined on the DB
// instance directly. The "hasOwnProperty" property is defined on Object.prototype, so we must
diff --git a/src/mongo/shell/encrypted_dbclient_base.cpp b/src/mongo/shell/encrypted_dbclient_base.cpp
index b9151685a93..137d0c482ab 100644
--- a/src/mongo/shell/encrypted_dbclient_base.cpp
+++ b/src/mongo/shell/encrypted_dbclient_base.cpp
@@ -199,24 +199,22 @@ void EncryptedDBClientBase::decryptPayload(ConstDataRange data,
}
}
-EncryptedDBClientBase::RunCommandReturn EncryptedDBClientBase::processResponseFLE1(
- EncryptedDBClientBase::RunCommandReturn result, const StringData databaseName) {
- auto rawReply = result.returnReply->getCommandReply();
+std::pair<rpc::UniqueReply, DBClientBase*> EncryptedDBClientBase::processResponseFLE1(
+ rpc::UniqueReply result, const StringData databaseName) {
+ auto rawReply = result->getCommandReply();
return prepareReply(
std::move(result), databaseName, encryptDecryptCommand(rawReply, false, databaseName));
}
-EncryptedDBClientBase::RunCommandReturn EncryptedDBClientBase::processResponseFLE2(
- EncryptedDBClientBase::RunCommandReturn result, const StringData databaseName) {
- auto rawReply = result.returnReply->getCommandReply();
+std::pair<rpc::UniqueReply, DBClientBase*> EncryptedDBClientBase::processResponseFLE2(
+ rpc::UniqueReply result, const StringData databaseName) {
+ auto rawReply = result->getCommandReply();
return prepareReply(
std::move(result), databaseName, FLEClientCrypto::decryptDocument(rawReply, this));
}
-EncryptedDBClientBase::RunCommandReturn EncryptedDBClientBase::prepareReply(
- EncryptedDBClientBase::RunCommandReturn result,
- const StringData databaseName,
- BSONObj decryptedDoc) {
+std::pair<rpc::UniqueReply, DBClientBase*> EncryptedDBClientBase::prepareReply(
+ rpc::UniqueReply result, const StringData databaseName, BSONObj decryptedDoc) {
rpc::OpMsgReplyBuilder replyBuilder;
replyBuilder.setCommandReply(StatusWith<BSONObj>(decryptedDoc));
auto msg = replyBuilder.done();
@@ -224,49 +222,22 @@ EncryptedDBClientBase::RunCommandReturn EncryptedDBClientBase::prepareReply(
auto host = _conn->getServerAddress();
auto reply = _conn->parseCommandReplyMessage(host, msg);
- return EncryptedDBClientBase::RunCommandReturn({std::move(reply), result});
+ return {std::move(reply), this};
}
-EncryptedDBClientBase::RunCommandReturn EncryptedDBClientBase::doRunCommand(
- EncryptedDBClientBase::RunCommandParams params) {
- if (params.type == EncryptedDBClientBase::RunCommandConnectionType::rawPtr) {
- return EncryptedDBClientBase::RunCommandReturn(
- _conn->runCommandWithTarget(std::move(params.request)));
- }
- invariant(params.conn);
- return EncryptedDBClientBase::RunCommandReturn(
- _conn->runCommandWithTarget(std::move(params.request), params.conn));
-}
-
-EncryptedDBClientBase::RunCommandReturn EncryptedDBClientBase::handleEncryptionRequest(
- EncryptedDBClientBase::RunCommandParams params) {
- auto commandName = params.request.getCommandName().toString();
- auto databaseName = params.request.getDatabase().toString();
+std::pair<rpc::UniqueReply, DBClientBase*> EncryptedDBClientBase::runCommandWithTarget(
+ OpMsgRequest request) {
+ std::string commandName = request.getCommandName().toString();
+ std::string databaseName = request.getDatabase().toString();
if (std::find(kEncryptedCommands.begin(), kEncryptedCommands.end(), StringData(commandName)) ==
std::end(kEncryptedCommands)) {
- return doRunCommand(std::move(params));
+ return _conn->runCommandWithTarget(std::move(request));
}
- EncryptedDBClientBase::RunCommandReturn result(doRunCommand(std::move(params)));
- return processResponseFLE1(processResponseFLE2(std::move(result), databaseName), databaseName);
-}
-
-std::pair<rpc::UniqueReply, DBClientBase*> EncryptedDBClientBase::runCommandWithTarget(
- OpMsgRequest request) {
- EncryptedDBClientBase::RunCommandParams params(request);
- auto result = handleEncryptionRequest(std::move(params));
- auto returnConn = stdx::get<DBClientBase*>(result.returnConn);
- return {std::move(result.returnReply), returnConn};
-}
-
-std::pair<rpc::UniqueReply, std::shared_ptr<DBClientBase>>
-EncryptedDBClientBase::runCommandWithTarget(OpMsgRequest request,
- std::shared_ptr<DBClientBase> conn) {
- EncryptedDBClientBase::RunCommandParams params(request, conn);
- auto result = handleEncryptionRequest(std::move(params));
- auto returnConn = stdx::get<std::shared_ptr<DBClientBase>>(result.returnConn);
- return {std::move(result.returnReply), returnConn};
+ auto result = _conn->runCommandWithTarget(std::move(request)).first;
+ return processResponseFLE1(processResponseFLE2(std::move(result), databaseName).first,
+ databaseName);
}
/**
@@ -715,10 +686,6 @@ std::shared_ptr<SymmetricKey> EncryptedDBClientBase::getDataKey(const UUID& uuid
return key;
}
-DBClientBase* EncryptedDBClientBase::getRawConnection() {
- return _conn.get();
-}
-
SecureVector<uint8_t> EncryptedDBClientBase::getKeyMaterialFromDisk(const UUID& uuid) {
NamespaceString fullNameNS = getCollectionNS();
FindCommandRequest findCmd{fullNameNS};
@@ -899,16 +866,8 @@ std::unique_ptr<DBClientBase> createEncryptedDBClientBase(std::unique_ptr<DBClie
return std::move(base);
}
-DBClientBase* getNestedConnection(DBClientBase* conn) {
- auto* encryptedConn = dynamic_cast<EncryptedDBClientBase*>(conn);
- if (!encryptedConn) {
- return nullptr;
- }
- return encryptedConn->getRawConnection();
-}
-
MONGO_INITIALIZER(setCallbacksForEncryptedDBClientBase)(InitializerContext*) {
- mongo::mozjs::setEncryptedDBClientCallbacks(createEncryptedDBClientBase, getNestedConnection);
+ mongo::mozjs::setEncryptedDBClientCallback(createEncryptedDBClientBase);
}
} // namespace
diff --git a/src/mongo/shell/encrypted_dbclient_base.h b/src/mongo/shell/encrypted_dbclient_base.h
index f7a7608f70a..4c0a75434fb 100644
--- a/src/mongo/shell/encrypted_dbclient_base.h
+++ b/src/mongo/shell/encrypted_dbclient_base.h
@@ -102,11 +102,7 @@ public:
using DBClientBase::runCommandWithTarget;
virtual std::pair<rpc::UniqueReply, DBClientBase*> runCommandWithTarget(
- OpMsgRequest request) final;
-
- std::pair<rpc::UniqueReply, std::shared_ptr<DBClientBase>> runCommandWithTarget(
- OpMsgRequest request, std::shared_ptr<DBClientBase>) final;
-
+ OpMsgRequest request) override;
std::string toString() const final;
int getMinWireVersion() final;
@@ -157,8 +153,6 @@ public:
bool isMongos() const final;
- DBClientBase* getRawConnection();
-
#ifdef MONGO_CONFIG_SSL
const SSLConfiguration* getSSLConfiguration() override;
@@ -170,54 +164,16 @@ public:
protected:
BSONObj _decryptResponsePayload(BSONObj& reply, StringData databaseName, bool isFLE2);
- enum class RunCommandConnectionType { rawPtr, sharedPtr };
-
- struct RunCommandParams {
- OpMsgRequest request;
- std::shared_ptr<DBClientBase> conn;
- RunCommandConnectionType type;
-
- RunCommandParams(OpMsgRequest request)
- : request(std::move(request)), type(RunCommandConnectionType::rawPtr){};
-
- RunCommandParams(OpMsgRequest request, std::shared_ptr<DBClientBase> base)
- : request(std::move(request)), conn(base), type(RunCommandConnectionType::sharedPtr){};
-
- RunCommandParams(OpMsgRequest request, RunCommandParams params)
- : request(std::move(request)), type(params.type) {
- if (type == RunCommandConnectionType::sharedPtr) {
- conn = params.conn;
- };
- };
- };
-
- using RunCommandReturnConn = stdx::variant<DBClientBase*, std::shared_ptr<DBClientBase>>;
-
- struct RunCommandReturn {
- rpc::UniqueReply returnReply;
- RunCommandReturnConn returnConn;
-
- RunCommandReturn(std::pair<rpc::UniqueReply, DBClientBase*> pair)
- : returnReply(std::move(std::get<0>(pair))), returnConn(std::get<1>(pair)) {}
-
- RunCommandReturn(std::pair<rpc::UniqueReply, std::shared_ptr<DBClientBase>> pair)
- : returnReply(std::move(std::get<0>(pair))), returnConn(std::get<1>(pair)) {}
-
- RunCommandReturn(rpc::UniqueReply reply, RunCommandReturn& result)
- : returnReply(std::move(reply)), returnConn(result.returnConn) {}
- };
-
- RunCommandReturn doRunCommand(RunCommandParams params);
-
- virtual RunCommandReturn handleEncryptionRequest(RunCommandParams params);
+ std::pair<rpc::UniqueReply, DBClientBase*> processResponseFLE1(rpc::UniqueReply result,
+ StringData databaseName);
- RunCommandReturn processResponseFLE1(RunCommandReturn result, StringData databaseName);
+ std::pair<rpc::UniqueReply, DBClientBase*> processResponseFLE2(rpc::UniqueReply result,
+ StringData databaseName);
- RunCommandReturn processResponseFLE2(RunCommandReturn result, StringData DatabaseName);
+ std::pair<rpc::UniqueReply, DBClientBase*> prepareReply(rpc::UniqueReply result,
+ StringData databaseName,
+ BSONObj decryptedDoc);
- RunCommandReturn prepareReply(RunCommandReturn result,
- StringData databaseName,
- BSONObj decryptedDoc);
BSONObj encryptDecryptCommand(const BSONObj& object, bool encrypt, StringData databaseName);
diff --git a/src/mongo/shell/keyvault.js b/src/mongo/shell/keyvault.js
index ee8f2ddf111..c913d81a5b1 100644
--- a/src/mongo/shell/keyvault.js
+++ b/src/mongo/shell/keyvault.js
@@ -6,37 +6,13 @@ Mongo.prototype.getKeyVault = function() {
};
class KeyVault {
- _runCommand(client, func, args) {
- let numRetries = 3;
- do {
- try {
- const result = func.apply(client, args);
- return result;
- } catch (e) {
- numRetries--;
- if (!isNetworkError(e) || numRetries == 0) {
- jsTest.log("KeyVault: We have exceeded the number of retries. Throwing.");
- throw e;
- }
-
- const res = this.mongo.getDB('admin')._helloOrLegacyHello();
- if (!res) {
- jsTest.log("KeyVault: We do not have a connection to the database. Throwing.");
- throw e;
- }
- this.keyColl = this.mongo.getDataKeyCollection();
- }
- } while (true);
- }
-
constructor(mongo) {
this.mongo = mongo;
- var collection = this._runCommand(this.mongo, this.mongo.getDataKeyCollection, {});
+ var collection = mongo.getDataKeyCollection();
this.keyColl = collection;
- this._runCommand(this.keyColl, this.keyColl.createIndex, [
+ this.keyColl.createIndex(
{keyAltNames: 1},
- {unique: true, partialFilterExpression: {keyAltNames: {$exists: true}}}
- ]);
+ {unique: true, partialFilterExpression: {keyAltNames: {$exists: true}}});
}
createKey(kmsProvider, param2 = undefined, param3 = undefined) {
@@ -59,8 +35,7 @@ class KeyVault {
return "TypeError: customer master key must be of String type.";
}
- var masterKeyAndMaterial = this._runCommand(
- this.mongo, this.mongo.generateDataKey, [kmsProvider, customerMasterKey]);
+ var masterKeyAndMaterial = this.mongo.generateDataKey(kmsProvider, customerMasterKey);
var masterKey = masterKeyAndMaterial.masterKey;
var current = ISODate();
@@ -91,24 +66,24 @@ class KeyVault {
doc.keyAltNames = keyAltNames;
}
- this._runCommand(this.keyColl, this.keyColl.insert, [doc]);
+ this.keyColl.insert(doc);
return uuid;
}
getKey(keyId) {
- return this._runCommand(this.keyColl, this.keyColl.find, [{"_id": keyId}]);
+ return this.keyColl.find({"_id": keyId});
}
getKeyByAltName(keyAltName) {
- return this._runCommand(this.keyColl, this.keyColl.find, [{"keyAltNames": keyAltName}]);
+ return this.keyColl.find({"keyAltNames": keyAltName});
}
deleteKey(keyId) {
- return this._runCommand(this.keyColl, this.keyColl.deleteOne, [{"_id": keyId}]);
+ return this.keyColl.deleteOne({"_id": keyId});
}
getKeys() {
- return this._runCommand(this.keyColl, this.keyColl.find, []);
+ return this.keyColl.find();
}
addKeyAlternateName(keyId, keyAltName) {
@@ -117,31 +92,27 @@ class KeyVault {
if (typeof keyAltName === "object") {
return "TypeError: key alternate name cannot be object or array type.";
}
- return this._runCommand(
- this.keyColl, this.keyColl.findAndModify, [{
- query: {"_id": keyId},
- update: {$push: {"keyAltNames": keyAltName}, $currentDate: {"updateDate": true}},
- }]);
+ return this.keyColl.findAndModify({
+ query: {"_id": keyId},
+ update: {$push: {"keyAltNames": keyAltName}, $currentDate: {"updateDate": true}},
+ });
}
removeKeyAlternateName(keyId, keyAltName) {
if (typeof keyAltName === "object") {
return "TypeError: key alternate name cannot be object or array type.";
}
-
- const ret = this._runCommand(
- this.keyColl, this.keyColl.findAndModify, [{
- query: {"_id": keyId},
- update: {$pull: {"keyAltNames": keyAltName}, $currentDate: {"updateDate": true}}
- }]);
+ const ret = this.keyColl.findAndModify({
+ query: {"_id": keyId},
+ update: {$pull: {"keyAltNames": keyAltName}, $currentDate: {"updateDate": true}}
+ });
if (ret != null && ret.keyAltNames.length === 1 && ret.keyAltNames[0] === keyAltName) {
// Remove the empty array to prevent duplicate key violations
- return this._runCommand(
- this.keyColl, this.keyColl.findAndModify, [{
- query: {"_id": keyId, "keyAltNames": undefined},
- update: {$unset: {"keyAltNames": ""}, $currentDate: {"updateDate": true}}
- }]);
+ return this.keyColl.findAndModify({
+ query: {"_id": keyId, "keyAltNames": undefined},
+ update: {$unset: {"keyAltNames": ""}, $currentDate: {"updateDate": true}}
+ });
}
return ret;
}
diff --git a/src/mongo/shell/linenoise.cpp b/src/mongo/shell/linenoise.cpp
index d62082aa089..679578d133b 100644
--- a/src/mongo/shell/linenoise.cpp
+++ b/src/mongo/shell/linenoise.cpp
@@ -119,7 +119,6 @@
#include <string>
#include <vector>
-#include "mongo/base/data_view.h"
#include "mongo/util/errno_util.h"
using std::string;
@@ -353,7 +352,7 @@ public:
}
Utf32String killedText(text, textLen);
if (lastAction == actionKill && size > 0) {
- int slot = mongo::ConstDataView(&indexToSlot[0]).read<uint8_t>();
+ int slot = indexToSlot[0];
int currentLen = theRing[slot].length();
int resultLen = currentLen + textLen;
Utf32String temp(resultLen + 1);
@@ -376,7 +375,7 @@ public:
size++;
theRing.push_back(killedText);
} else {
- int slot = mongo::ConstDataView(&indexToSlot[capacity - 1]).read<uint8_t>();
+ int slot = indexToSlot[capacity - 1];
theRing[slot] = killedText;
memmove(&indexToSlot[1], &indexToSlot[0], capacity - 1);
indexToSlot[0] = slot;
diff --git a/src/mongo/shell/mongo_main.cpp b/src/mongo/shell/mongo_main.cpp
index 6d3b5f37244..b6cac96d526 100644
--- a/src/mongo/shell/mongo_main.cpp
+++ b/src/mongo/shell/mongo_main.cpp
@@ -116,14 +116,14 @@ const std::string kDefaultMongoURL = "mongodb://"s + kDefaultMongoHost + ":"s +
// level. The server is responsible for rejecting usages of new features if its
// featureCompatibilityVersion is lower.
MONGO_INITIALIZER_WITH_PREREQUISITES(SetFeatureCompatibilityVersionLatest,
- ("EndStartupOptionStorage"))
+ ("EndStartupOptionSetup"))
// (Generic FCV reference): This FCV reference should exist across LTS binary versions.
(InitializerContext* context) {
mongo::serverGlobalParams.mutableFeatureCompatibility.setVersion(
multiversion::GenericFCV::kLatest);
}
-MONGO_INITIALIZER_WITH_PREREQUISITES(WireSpec, ("EndStartupOptionHandling"))(InitializerContext*) {
+MONGO_INITIALIZER_WITH_PREREQUISITES(WireSpec, ("EndStartupOptionSetup"))(InitializerContext*) {
WireSpec::instance().initialize(WireSpec::Specification{});
}
@@ -1005,6 +1005,12 @@ int mongo_main(int argc, char* argv[]) {
true,
false);
+ scope->exec("shellHelper( 'show', 'freeMonitoring' )",
+ "(freeMonitoring)",
+ false,
+ true,
+ false);
+
scope->exec("shellHelper( 'show', 'automationNotices' )",
"(automationnotices)",
false,
diff --git a/src/mongo/shell/query.js b/src/mongo/shell/query.js
index b43e13c23e8..a5d920cb109 100644
--- a/src/mongo/shell/query.js
+++ b/src/mongo/shell/query.js
@@ -98,10 +98,6 @@ DBQuery.prototype._canUseCommandCursor = function() {
(this._options & DBQuery.Option.exhaust) === 0;
};
-DBQuery.prototype._isTailableCursor = function() {
- return (this._options & DBQuery.Option.tailable) !== 0;
-};
-
/**
* This method is exposed only for the purpose of testing and should not be used in most contexts.
*
@@ -305,9 +301,7 @@ DBQuery.prototype.skip = function(skip) {
DBQuery.prototype.hasNext = function() {
this._exec();
- // Return when limit is reached for tailable cursors. For other cursor options, like an exhaust
- // cursor, the server manages closing.
- if (this._isTailableCursor() && this._limit > 0 && this._cursorSeen >= this._limit) {
+ if (this._limit > 0 && this._cursorSeen >= this._limit) {
this._cursor.close();
return false;
}
diff --git a/src/mongo/shell/replsettest.js b/src/mongo/shell/replsettest.js
index a22c5142419..827691f822d 100644
--- a/src/mongo/shell/replsettest.js
+++ b/src/mongo/shell/replsettest.js
@@ -656,9 +656,6 @@ var ReplSetTest = function(opts) {
// replica set nodes and return without waiting to connect to any of them.
const skipWaitingForAllConnections = (options && options.waitForConnect === false);
- // Keep a copy of these options
- self.startSetOptions = options;
-
// Start up without waiting for connections.
this.startSetAsync(options, restart);
@@ -733,8 +730,8 @@ var ReplSetTest = function(opts) {
/**
* Blocks until the secondary nodes have completed recovery and their roles are known. Blocks on
- * all secondary nodes or just 'secondaries', if specified. Does not wait for all 'newlyAdded'
- * fields to be removed by default.
+ * all secondary nodes or just 'secondaries', if specified. Waits for all 'newlyAdded' fields to
+ * be removed by default.
*/
this.awaitSecondaryNodes = function(
timeout, secondaries, retryIntervalMS, waitForNewlyAddedRemoval) {
@@ -1364,28 +1361,6 @@ var ReplSetTest = function(opts) {
cmd[cmdKey] = config;
- // If this ReplSet is started using this.startSet and binVersions (ie:
- // rst.startSet({binVersion: [...]}) we need to make sure the binVersion combination is
- // valid.
- if (typeof (this.startSetOptions) === "object" &&
- this.startSetOptions.hasOwnProperty("binVersion") &&
- typeof (this.startSetOptions.binVersion) === "object") {
- let lastLTSSpecified = false;
- let lastContinuousSpecified = false;
- this.startSetOptions.binVersion.forEach(function(binVersion, _) {
- if (lastLTSSpecified === false) {
- lastLTSSpecified = MongoRunner.areBinVersionsTheSame(binVersion, lastLTSFCV);
- }
- if ((lastContinuousSpecified === false) && (lastLTSFCV !== lastContinuousFCV)) {
- lastContinuousSpecified =
- MongoRunner.areBinVersionsTheSame(binVersion, lastContinuousFCV);
- }
- });
- if (lastLTSSpecified && lastContinuousSpecified) {
- throw new Error("Can only specify one of 'last-lts' and 'last-continuous' " +
- "in binVersion, not both.");
- }
- }
// Initiating a replica set with a single node will use "latest" FCV. This will
// cause IncompatibleServerVersion errors if additional "last-lts"/"last-continuous" binary
// version nodes are subsequently added to the set, since such nodes cannot set their FCV to
@@ -1397,15 +1372,11 @@ var ReplSetTest = function(opts) {
Object.keys(this.nodeOptions).forEach(function(key, index) {
let val = self.nodeOptions[key];
if (typeof (val) === "object" && val.hasOwnProperty("binVersion")) {
- if (lastLTSBinVersionWasSpecifiedForSomeNode === false) {
- lastLTSBinVersionWasSpecifiedForSomeNode =
- MongoRunner.areBinVersionsTheSame(val.binVersion, lastLTSFCV);
- }
- if ((lastContinuousBinVersionWasSpecifiedForSomeNode === false) &&
- (lastLTSFCV !== lastContinuousFCV)) {
- lastContinuousBinVersionWasSpecifiedForSomeNode =
- MongoRunner.areBinVersionsTheSame(val.binVersion, lastContinuousFCV);
- }
+ lastLTSBinVersionWasSpecifiedForSomeNode =
+ MongoRunner.areBinVersionsTheSame(val.binVersion, lastLTSFCV);
+ lastContinuousBinVersionWasSpecifiedForSomeNode =
+ (lastLTSFCV !== lastContinuousFCV) &&
+ MongoRunner.areBinVersionsTheSame(val.binVersion, lastContinuousFCV);
explicitBinVersionWasSpecifiedForSomeNode = true;
}
});
@@ -1835,19 +1806,13 @@ var ReplSetTest = function(opts) {
const timeout = 60 * 1000;
this.awaitNodesAgreeOnPrimary(timeout, this.nodes, node);
- if (!awaitWritablePrimary) {
- return true;
- }
-
// getPrimary() guarantees that there will be only one writable primary for a replica
// set.
- const newPrimary = this.getPrimary();
- if (newPrimary.host === node.host) {
+ if (!awaitWritablePrimary || this.getPrimary() === node) {
return true;
}
- jsTest.log(node.host + ' is not primary after stepUp command, ' + newPrimary.host +
- ' is the primary');
+ jsTest.log(node.host + ' is not primary after stepUp command');
return false;
}, "Timed out while waiting for stepUp to succeed on node in port: " + node.port);
diff --git a/src/mongo/shell/servers.js b/src/mongo/shell/servers.js
index ece24b66a6b..215e7ce3d37 100644
--- a/src/mongo/shell/servers.js
+++ b/src/mongo/shell/servers.js
@@ -25,6 +25,17 @@ var _parsePath = function() {
return dbpath;
};
+var _parsePort = function() {
+ var port = "";
+ for (var i = 0; i < arguments.length; ++i)
+ if (arguments[i] == "--port")
+ port = arguments[i + 1];
+
+ if (port == "")
+ throw Error("No port specified");
+ return port;
+};
+
var createMongoArgs = function(binaryName, args) {
if (!Array.isArray(args)) {
throw new Error("The second argument to createMongoArgs must be an array");
@@ -71,17 +82,6 @@ MongoRunner.mongosPath = "mongos";
MongoRunner.mongoqPath = "mongoqd";
MongoRunner.mongoShellPath = "mongo";
-MongoRunner.parsePort = function() {
- var port = "";
- for (var i = 0; i < arguments.length; ++i)
- if (arguments[i] == "--port")
- port = arguments[i + 1];
-
- if (port == "")
- throw Error("No port specified");
- return port;
-};
-
MongoRunner.VersionSub = function(pattern, version) {
this.pattern = pattern;
this.version = version;
@@ -1380,19 +1380,6 @@ function appendSetParameterArgs(argArray) {
argArray.push(...['--setParameter', "logComponentVerbosity=" + logVerbosityParam]);
}
- if (programMajorMinorVersion >= 530 &&
- !argArrayContainsSetParameterValue("backtraceLogFile=")) {
- let randomName = "";
- let randomStrLen = 20;
- const chars = "qwertyuiopasdfghjklzxcvbnm1234567890";
- for (let i = 0; i <= randomStrLen; i++) {
- randomName += chars[((Math.random() * 1000) % chars.length) ^ 0];
- }
- const backtraceLogFilePath =
- MongoRunner.dataDir + "/" + randomName + Date.now() + ".stacktrace";
- argArray.push(...["--setParameter", "backtraceLogFile=" + backtraceLogFilePath]);
- }
-
// When launching a 5.0 mongod, if we're mentioning the
// `storeFindAndModifyImagesInSideCollection` setParameter and the corresponding feature
// flag is not set, add it for good measure.
@@ -1640,7 +1627,7 @@ MongoRunner._startWithArgs = function(argArray, env, waitForConnect) {
// TODO: Make there only be one codepath for starting mongo processes
argArray = appendSetParameterArgs(argArray);
- var port = MongoRunner.parsePort.apply(null, argArray);
+ var port = _parsePort.apply(null, argArray);
var pid = -1;
if (env === undefined) {
pid = _startMongoProgram.apply(null, argArray);
@@ -1675,7 +1662,7 @@ MongoRunner._startWithArgs = function(argArray, env, waitForConnect) {
* command line arguments to the program.
*/
startMongoProgram = function() {
- var port = MongoRunner.parsePort.apply(null, arguments);
+ var port = _parsePort.apply(null, arguments);
// Enable test commands.
// TODO: Make this work better with multi-version testing so that we can support
diff --git a/src/mongo/shell/shardingtest.js b/src/mongo/shell/shardingtest.js
index 1319746ea1a..60f6e83fac7 100644
--- a/src/mongo/shell/shardingtest.js
+++ b/src/mongo/shell/shardingtest.js
@@ -10,7 +10,6 @@
*
* {
* name {string}: name for this test
- * shouldFailInit {boolean}: if set, assert that this will fail initialization
* verbose {number}: the verbosity for the mongos
* chunkSize {number}: the chunk size to use as configuration for the cluster
*
@@ -114,9 +113,6 @@ var ShardingTest = function(params) {
// concern (5 minutes)
var kDefaultWTimeoutMs = 5 * 60 * 1000;
- // Oplog collection name
- const kOplogName = 'oplog.rs';
-
// Ensure we don't mutate the passed-in parameters.
params = Object.extend({}, params, true);
@@ -408,24 +404,6 @@ var ShardingTest = function(params) {
(timeMillis / 1000) + " seconds ***");
};
- this.stopOnFail = function() {
- try {
- this.stopAllMongos();
- } catch (e) {
- print("Did not successfully stop all mongos.");
- }
- try {
- this.stopAllShards();
- } catch (e) {
- print("Did not successfully stop all shards.");
- }
- try {
- this.stopAllConfigServers();
- } catch (e) {
- print("Did not successfully stop all config servers.");
- }
- };
-
this.adminCommand = function(cmd) {
var res = this.admin.runCommand(cmd);
if (res && res.ok == 1)
@@ -597,12 +575,53 @@ var ShardingTest = function(params) {
};
/**
- * Waits up to the specified timeout (with a default of 60s) for the collection to be
- * considered well balanced.
- **/
- this.awaitBalance = function(collName, dbName, timeToWait, interval) {
- const coll = this.s.getCollection(dbName + "." + collName);
- this.awaitCollectionBalance(coll, timeToWait, interval);
+ * Waits up to the specified timeout (with a default of 60s) for the balancer to execute one
+ * round. If no round has been executed, throws an error.
+ *
+ * The mongosConnection parameter is optional and allows callers to specify a connection
+ * different than the first mongos instance in the list.
+ */
+ this.awaitBalancerRound = function(timeoutMs, mongosConnection) {
+ timeoutMs = timeoutMs || 60000;
+ mongosConnection = mongosConnection || self.s0;
+
+ // Get the balancer section from the server status of the config server primary
+ function getBalancerStatus() {
+ var balancerStatus =
+ assert.commandWorked(mongosConnection.adminCommand({balancerStatus: 1}));
+ if (balancerStatus.mode !== 'full') {
+ throw Error('Balancer is not enabled');
+ }
+
+ return balancerStatus;
+ }
+
+ var initialStatus = getBalancerStatus();
+ var currentStatus;
+ assert.soon(
+ function() {
+ currentStatus = getBalancerStatus();
+ return (currentStatus.numBalancerRounds - initialStatus.numBalancerRounds) != 0;
+ },
+ function() {
+ return 'Latest balancer status: ' + tojson(currentStatus);
+ },
+ timeoutMs);
+ };
+
+ /**
+ * Waits up to one minute for the difference in chunks between the most loaded shard and
+ * least loaded shard to be 0 or 1, indicating that the collection is well balanced. This should
+ * only be called after creating a big enough chunk difference to trigger balancing.
+ */
+ this.awaitBalance = function(collName, dbName, timeToWait) {
+ timeToWait = timeToWait || 60000;
+
+ assert.soon(function() {
+ var x = self.chunkDiff(collName, dbName);
+ print("chunk diff: " + x);
+ return x < 2;
+ }, "no balance happened", timeToWait);
};
this.getShard = function(coll, query, includeEmpty) {
@@ -995,24 +1014,6 @@ var ShardingTest = function(params) {
};
/**
- * Waits for all operations to fully replicate on all shards.
- */
- this.awaitReplicationOnShards = function() {
- this._rs.forEach(replSet => replSet.test.awaitReplication());
- };
-
- /**
- * Query the oplog from a given node.
- */
- ShardingTest.prototype.findOplog = function(conn, query, limit) {
- return conn.getDB('local')
- .getCollection(kOplogName)
- .find(query)
- .sort({$natural: -1})
- .limit(limit);
- };
-
- /**
* Returns if there is a new feature compatibility version for the "latest" version. This must
* be manually changed if and when there is a new feature compatibility version.
*/
@@ -1034,7 +1035,8 @@ var ShardingTest = function(params) {
assert(isObject(params), 'ShardingTest configuration must be a JSON object');
var testName = params.name || jsTest.name();
- var otherParams = Object.deepMerge(params, params.other || {});
+ var otherParams = Object.merge(params, params.other || {});
+
var numShards = otherParams.hasOwnProperty('shards') ? otherParams.shards : 2;
var mongosVerboseLevel = otherParams.hasOwnProperty('verbose') ? otherParams.verbose : 1;
var numMongos = otherParams.hasOwnProperty('mongos') ? otherParams.mongos : 1;
@@ -1184,551 +1186,537 @@ var ShardingTest = function(params) {
randomSeedAlreadySet = true;
}
- try {
- //
- // Start each shard replica set.
- //
- let startTime = new Date(); // Measure the execution time of startup and initiate.
- for (var i = 0; i < numShards; i++) {
- var setName = testName + "-rs" + i;
-
- var rsDefaults = {
- useHostname: otherParams.useHostname,
- oplogSize: 16,
- shardsvr: '',
- pathOpts: Object.merge(pathOpts, {shard: i}),
- };
+ //
+ // Start each shard replica set.
+ //
+ let startTime = new Date(); // Measure the execution time of startup and initiate.
+ for (var i = 0; i < numShards; i++) {
+ var setName = testName + "-rs" + i;
+
+ var rsDefaults = {
+ useHostname: otherParams.useHostname,
+ oplogSize: 16,
+ shardsvr: '',
+ pathOpts: Object.merge(pathOpts, {shard: i}),
+ };
- if (otherParams.rs || otherParams["rs" + i]) {
- if (otherParams.rs) {
- rsDefaults = Object.merge(rsDefaults, otherParams.rs);
- }
- if (otherParams["rs" + i]) {
- rsDefaults = Object.merge(rsDefaults, otherParams["rs" + i]);
- }
- rsDefaults = Object.merge(rsDefaults, otherParams.rsOptions);
- rsDefaults.nodes = rsDefaults.nodes || otherParams.numReplicas;
- } else {
- if (jsTestOptions().shardMixedBinVersions) {
- if (!otherParams.shardOptions) {
- otherParams.shardOptions = {};
- }
- // If the test doesn't depend on specific shard binVersions, create a mixed
- // version
- // shard cluster that randomly assigns shard binVersions, half "latest" and half
- // "last-continuous" or "last-lts".
- // shardMixedBinVersions.
- if (!otherParams.shardOptions.binVersion) {
- Random.setRandomSeed();
- otherParams.shardOptions.binVersion = MongoRunner.versionIterator(
- ["latest", jsTestOptions().shardMixedBinVersions], true);
- }
+ if (otherParams.rs || otherParams["rs" + i]) {
+ if (otherParams.rs) {
+ rsDefaults = Object.merge(rsDefaults, otherParams.rs);
+ }
+ if (otherParams["rs" + i]) {
+ rsDefaults = Object.merge(rsDefaults, otherParams["rs" + i]);
+ }
+ rsDefaults = Object.merge(rsDefaults, otherParams.rsOptions);
+ rsDefaults.nodes = rsDefaults.nodes || otherParams.numReplicas;
+ } else {
+ if (jsTestOptions().shardMixedBinVersions) {
+ if (!otherParams.shardOptions) {
+ otherParams.shardOptions = {};
}
-
- if (otherParams.shardOptions && otherParams.shardOptions.binVersion) {
- otherParams.shardOptions.binVersion =
- MongoRunner.versionIterator(otherParams.shardOptions.binVersion);
+ // If the test doesn't depend on specific shard binVersions, create a mixed
+ // version
+ // shard cluster that randomly assigns shard binVersions, half "latest" and half
+ // "last-continuous" or "last-lts".
+ // shardMixedBinVersions.
+ if (!otherParams.shardOptions.binVersion) {
+ Random.setRandomSeed();
+ otherParams.shardOptions.binVersion = MongoRunner.versionIterator(
+ ["latest", jsTestOptions().shardMixedBinVersions], true);
}
+ }
- rsDefaults = Object.merge(rsDefaults, otherParams["d" + i]);
- rsDefaults = Object.merge(rsDefaults, otherParams.shardOptions);
+ if (otherParams.shardOptions && otherParams.shardOptions.binVersion) {
+ otherParams.shardOptions.binVersion =
+ MongoRunner.versionIterator(otherParams.shardOptions.binVersion);
}
- rsDefaults.setParameter = rsDefaults.setParameter || {};
- rsDefaults.setParameter.migrationLockAcquisitionMaxWaitMS =
- otherParams.migrationLockAcquisitionMaxWaitMS;
+ rsDefaults = Object.merge(rsDefaults, otherParams["d" + i]);
+ rsDefaults = Object.merge(rsDefaults, otherParams.shardOptions);
+ }
- var rsSettings = rsDefaults.settings;
- delete rsDefaults.settings;
+ rsDefaults.setParameter = rsDefaults.setParameter || {};
+ rsDefaults.setParameter.migrationLockAcquisitionMaxWaitMS =
+ otherParams.migrationLockAcquisitionMaxWaitMS;
- // The number of nodes in the rs field will take priority.
- if (otherParams.rs || otherParams["rs" + i]) {
- var numReplicas = rsDefaults.nodes || 3;
- } else {
- var numReplicas = 1;
- }
- delete rsDefaults.nodes;
-
- var protocolVersion = rsDefaults.protocolVersion;
- delete rsDefaults.protocolVersion;
-
- var rs = new ReplSetTest({
- name: setName,
- nodes: numReplicas,
- host: hostName,
- useHostName: otherParams.useHostname,
- useBridge: otherParams.useBridge,
- bridgeOptions: otherParams.bridgeOptions,
- keyFile: this.keyFile,
- protocolVersion: protocolVersion,
- waitForKeys: false,
- settings: rsSettings,
- seedRandomNumberGenerator: !randomSeedAlreadySet,
- });
+ var rsSettings = rsDefaults.settings;
+ delete rsDefaults.settings;
- print("ShardingTest starting replica set for shard: " + setName);
-
- // Start up the replica set but don't wait for it to complete. This allows the startup
- // of each shard to proceed in parallel.
- this._rs[i] =
- {setName: setName, test: rs, nodes: rs.startSetAsync(rsDefaults), url: rs.getURL()};
+ // The number of nodes in the rs field will take priority.
+ if (otherParams.rs || otherParams["rs" + i]) {
+ var numReplicas = rsDefaults.nodes || 3;
+ } else {
+ var numReplicas = 1;
}
+ delete rsDefaults.nodes;
- //
- // Start up the config server replica set.
- //
+ var protocolVersion = rsDefaults.protocolVersion;
+ delete rsDefaults.protocolVersion;
- var rstOptions = {
- useHostName: otherParams.useHostname,
+ var rs = new ReplSetTest({
+ name: setName,
+ nodes: numReplicas,
host: hostName,
+ useHostName: otherParams.useHostname,
useBridge: otherParams.useBridge,
bridgeOptions: otherParams.bridgeOptions,
keyFile: this.keyFile,
+ protocolVersion: protocolVersion,
waitForKeys: false,
- name: testName + "-configRS",
+ settings: rsSettings,
seedRandomNumberGenerator: !randomSeedAlreadySet,
- isConfigServer: true,
- };
+ });
- // always use wiredTiger as the storage engine for CSRS
- var startOptions = {
- pathOpts: pathOpts,
- // Ensure that journaling is always enabled for config servers.
- journal: "",
- configsvr: "",
- storageEngine: "wiredTiger",
- };
+ print("ShardingTest starting replica set for shard: " + setName);
- if (otherParams.configOptions && otherParams.configOptions.binVersion) {
- otherParams.configOptions.binVersion =
- MongoRunner.versionIterator(otherParams.configOptions.binVersion);
- }
+ // Start up the replica set but don't wait for it to complete. This allows the startup
+ // of each shard to proceed in parallel.
+ this._rs[i] =
+ {setName: setName, test: rs, nodes: rs.startSetAsync(rsDefaults), url: rs.getURL()};
+ }
- startOptions = Object.merge(startOptions, otherParams.configOptions);
- rstOptions = Object.merge(rstOptions, otherParams.configReplSetTestOptions);
+ //
+ // Start up the config server replica set.
+ //
+
+ var rstOptions = {
+ useHostName: otherParams.useHostname,
+ host: hostName,
+ useBridge: otherParams.useBridge,
+ bridgeOptions: otherParams.bridgeOptions,
+ keyFile: this.keyFile,
+ waitForKeys: false,
+ name: testName + "-configRS",
+ seedRandomNumberGenerator: !randomSeedAlreadySet,
+ isConfigServer: true,
+ };
- var nodeOptions = [];
- for (var i = 0; i < numConfigs; ++i) {
- nodeOptions.push(otherParams["c" + i] || {});
- }
+ // always use wiredTiger as the storage engine for CSRS
+ var startOptions = {
+ pathOpts: pathOpts,
+ // Ensure that journaling is always enabled for config servers.
+ journal: "",
+ configsvr: "",
+ storageEngine: "wiredTiger",
+ };
- rstOptions.nodes = nodeOptions;
+ if (otherParams.configOptions && otherParams.configOptions.binVersion) {
+ otherParams.configOptions.binVersion =
+ MongoRunner.versionIterator(otherParams.configOptions.binVersion);
+ }
- // Start the config server's replica set without waiting for it to complete. This allows it
- // to proceed in parallel with the startup of each shard.
- this.configRS = new ReplSetTest(rstOptions);
- this.configRS.startSetAsync(startOptions);
+ startOptions = Object.merge(startOptions, otherParams.configOptions);
+ rstOptions = Object.merge(rstOptions, otherParams.configReplSetTestOptions);
- //
- // Wait for each shard replica set to finish starting up.
- //
- for (let i = 0; i < numShards; i++) {
- print("Waiting for shard " + this._rs[i].setName + " to finish starting up.");
- this._rs[i].test.startSetAwait();
- }
-
- //
- // Wait for the config server to finish starting up.
- //
- print("Waiting for the config server to finish starting up.");
- this.configRS.startSetAwait();
- var config = this.configRS.getReplSetConfig();
- config.configsvr = true;
- config.settings = config.settings || {};
-
- print("ShardingTest startup for all nodes took " + (new Date() - startTime) + "ms with " +
- this.configRS.nodeList().length + " config server nodes and " + totalNumShardNodes() +
- " total shard nodes.");
-
- //
- // Initiate each shard replica set and wait for replication. Also initiate the config
- // replica set. Whenever possible, in parallel.
- //
- const shardsRS = this._rs.map(obj => obj.test);
- const replicaSetsToInitiate = [...shardsRS, this.configRS].map(rst => {
- const rstConfig = rst.getReplSetConfig();
-
- // The mongo shell cannot authenticate as the internal __system user in tests that use
- // x509 for cluster authentication. Choosing the default value for
- // wcMajorityJournalDefault in ReplSetTest cannot be done automatically without the
- // shell performing such authentication, so allow tests to pass the value in.
- if (otherParams.hasOwnProperty("writeConcernMajorityJournalDefault")) {
- rstConfig.writeConcernMajorityJournalDefault =
- otherParams.writeConcernMajorityJournalDefault;
- }
+ var nodeOptions = [];
+ for (var i = 0; i < numConfigs; ++i) {
+ nodeOptions.push(otherParams["c" + i] || {});
+ }
- if (rst === this.configRS) {
- rstConfig.configsvr = true;
- rstConfig.writeConcernMajorityJournalDefault = true;
- }
+ rstOptions.nodes = nodeOptions;
- return {
- rst,
- // Arguments for creating instances of each replica set within parallel threads.
- rstArgs: {
- name: rst.name,
- nodeHosts: rst.nodes.map(node => `127.0.0.1:${node.port}`),
- nodeOptions: rst.nodeOptions,
- // Mixed-mode SSL tests may specify a keyFile per replica set rather than one
- // for the whole cluster.
- keyFile: rst.keyFile ? rst.keyFile : this.keyFile,
- host: otherParams.useHostname ? hostName : "localhost",
- waitForKeys: false,
- },
- // Replica set configuration for initiating the replica set.
- rstConfig,
- };
- });
+ // Start the config server's replica set without waiting for it to complete. This allows it
+ // to proceed in parallel with the startup of each shard.
+ this.configRS = new ReplSetTest(rstOptions);
+ this.configRS.startSetAsync(startOptions);
- const initiateReplicaSet = (rst, rstConfig) => {
- rst.initiateWithAnyNodeAsPrimary(rstConfig);
+ //
+ // Wait for each shard replica set to finish starting up.
+ //
+ for (let i = 0; i < numShards; i++) {
+ print("Waiting for shard " + this._rs[i].setName + " to finish starting up.");
+ this._rs[i].test.startSetAwait();
+ }
- // Do replication.
- rst.awaitNodesAgreeOnPrimary();
- rst.getPrimary().getDB("admin").foo.save({x: 1});
- if (rst.keyFile) {
- authutil.asCluster(rst.nodes, rst.keyFile, function() {
- rst.awaitReplication();
- });
- }
- rst.awaitSecondaryNodes();
+ //
+ // Wait for the config server to finish starting up.
+ //
+ print("Waiting for the config server to finish starting up.");
+ this.configRS.startSetAwait();
+ var config = this.configRS.getReplSetConfig();
+ config.configsvr = true;
+ config.settings = config.settings || {};
+
+ print("ShardingTest startup for all nodes took " + (new Date() - startTime) + "ms with " +
+ this.configRS.nodeList().length + " config server nodes and " + totalNumShardNodes() +
+ " total shard nodes.");
+
+ //
+ // Initiate each shard replica set and wait for replication. Also initiate the config replica
+ // set. Whenever possible, in parallel.
+ //
+ const shardsRS = this._rs.map(obj => obj.test);
+ const replicaSetsToInitiate = [...shardsRS, this.configRS].map(rst => {
+ const rstConfig = rst.getReplSetConfig();
+
+ // The mongo shell cannot authenticate as the internal __system user in tests that use x509
+ // for cluster authentication. Choosing the default value for wcMajorityJournalDefault in
+ // ReplSetTest cannot be done automatically without the shell performing such
+ // authentication, so allow tests to pass the value in.
+ if (otherParams.hasOwnProperty("writeConcernMajorityJournalDefault")) {
+ rstConfig.writeConcernMajorityJournalDefault =
+ otherParams.writeConcernMajorityJournalDefault;
+ }
+
+ if (rst === this.configRS) {
+ rstConfig.configsvr = true;
+ rstConfig.writeConcernMajorityJournalDefault = true;
+ }
+
+ return {
+ rst,
+ // Arguments for creating instances of each replica set within parallel threads.
+ rstArgs: {
+ name: rst.name,
+ nodeHosts: rst.nodes.map(node => `127.0.0.1:${node.port}`),
+ nodeOptions: rst.nodeOptions,
+ // Mixed-mode SSL tests may specify a keyFile per replica set rather than one for
+ // the whole cluster.
+ keyFile: rst.keyFile ? rst.keyFile : this.keyFile,
+ host: otherParams.useHostname ? hostName : "localhost",
+ waitForKeys: false,
+ },
+ // Replica set configuration for initiating the replica set.
+ rstConfig,
};
+ });
- const isParallelSupported = (() => {
- if (!tryLoadParallelTester()) {
- return false;
- }
+ const initiateReplicaSet = (rst, rstConfig) => {
+ rst.initiateWithAnyNodeAsPrimary(rstConfig);
- for (let {rst} of replicaSetsToInitiate) {
- if (rst.startOptions && rst.startOptions.clusterAuthMode === "x509") {
- // The mongo shell performing X.509 authentication as a cluster member requires
- // starting a parallel shell and using the server's (not the client's)
- // certificate. The ReplSetTest instance constructed in a Thread wouldn't have
- // copied the path to the server's certificate. We therefore fall back to
- // initiating the CSRS and replica set shards sequentially when X.509
- // authentication is being used.
- return false;
- }
+ // Do replication.
+ rst.awaitNodesAgreeOnPrimary();
+ rst.getPrimary().getDB("admin").foo.save({x: 1});
+ if (rst.keyFile) {
+ authutil.asCluster(rst.nodes, rst.keyFile, function() {
+ rst.awaitReplication();
+ });
+ }
+ rst.awaitSecondaryNodes();
+ };
- for (let n of Object.keys(rst.nodeOptions)) {
- const nodeOptions = rst.nodeOptions[n];
- if (nodeOptions && nodeOptions.clusterAuthMode === "x509") {
- return false;
- }
- }
- }
+ const isParallelSupported = (() => {
+ if (!tryLoadParallelTester()) {
+ return false;
+ }
- return true;
- })();
+ for (let {rst} of replicaSetsToInitiate) {
+ if (rst.startOptions && rst.startOptions.clusterAuthMode === "x509") {
+ // The mongo shell performing X.509 authentication as a cluster member requires
+ // starting a parallel shell and using the server's (not the client's) certificate.
+ // The ReplSetTest instance constructed in a Thread wouldn't have copied the path to
+ // the server's certificate. We therefore fall back to initiating the CSRS and
+ // replica set shards sequentially when X.509 authentication is being used.
+ return false;
+ }
- if (isParallelSupported) {
- const threads = [];
- try {
- for (let {rstArgs, rstConfig} of replicaSetsToInitiate) {
- const thread = new Thread((rstArgs, rstConfig, initiateReplicaSet) => {
- try {
- const rst = new ReplSetTest({rstArgs});
- initiateReplicaSet(rst, rstConfig);
- return {ok: 1};
- } catch (e) {
- return {
- ok: 0,
- hosts: rstArgs.nodeHosts,
- name: rstArgs.name,
- error: e.toString(),
- stack: e.stack,
- };
- }
- }, rstArgs, rstConfig, initiateReplicaSet);
- thread.start();
- threads.push(thread);
+ for (let n of Object.keys(rst.nodeOptions)) {
+ const nodeOptions = rst.nodeOptions[n];
+ if (nodeOptions && nodeOptions.clusterAuthMode === "x509") {
+ return false;
}
- } finally {
- // Wait for each thread to finish. Throw an error if any thread fails.
- const returnData = threads.map(thread => {
- thread.join();
- return thread.returnData();
- });
-
- returnData.forEach(res => {
- assert.commandWorked(
- res, 'Initiating shard or config servers as a replica set failed');
- });
- }
- } else {
- for (let {rst, rstConfig} of replicaSetsToInitiate) {
- initiateReplicaSet(rst, rstConfig);
}
}
- for (let i = 0; i < numShards; i++) {
- let rs = this._rs[i].test;
-
- this["rs" + i] = rs;
- this._rsObjects[i] = rs;
-
- this._connections.push(null);
+ return true;
+ })();
- let rsConn = new Mongo(rs.getURL());
- rsConn.name = rs.getURL();
+ if (isParallelSupported) {
+ const threads = [];
+ try {
+ for (let {rstArgs, rstConfig} of replicaSetsToInitiate) {
+ const thread = new Thread((rstArgs, rstConfig, initiateReplicaSet) => {
+ try {
+ const rst = new ReplSetTest({rstArgs});
+ initiateReplicaSet(rst, rstConfig);
+ return {ok: 1};
+ } catch (e) {
+ return {
+ ok: 0,
+ hosts: rstArgs.nodeHosts,
+ name: rstArgs.name,
+ error: e.toString(),
+ stack: e.stack,
+ };
+ }
+ }, rstArgs, rstConfig, initiateReplicaSet);
+ thread.start();
+ threads.push(thread);
+ }
+ } finally {
+ // Wait for each thread to finish. Throw an error if any thread fails.
+ const returnData = threads.map(thread => {
+ thread.join();
+ return thread.returnData();
+ });
- this._connections[i] = rsConn;
- this["shard" + i] = rsConn;
- rsConn.rs = rs;
+ returnData.forEach(res => {
+ assert.commandWorked(res,
+ 'Initiating shard or config servers as a replica set failed');
+ });
+ }
+ } else {
+ for (let {rst, rstConfig} of replicaSetsToInitiate) {
+ initiateReplicaSet(rst, rstConfig);
}
+ }
- // Wait for master to be elected before starting mongos
- this.configRS.awaitNodesAgreeOnPrimary();
- var csrsPrimary = this.configRS.getPrimary();
+ for (let i = 0; i < numShards; i++) {
+ let rs = this._rs[i].test;
- print("ShardingTest startup and initiation for all nodes took " + (new Date() - startTime) +
- "ms with " + this.configRS.nodeList().length + " config server nodes and " +
- totalNumShardNodes() + " total shard nodes.");
+ this["rs" + i] = rs;
+ this._rsObjects[i] = rs;
- // If 'otherParams.mongosOptions.binVersion' is an array value, then we'll end up
- // constructing a version iterator.
- const mongosOptions = [];
- for (var i = 0; i < numMongos; ++i) {
- let options = {
- useHostname: otherParams.useHostname,
- pathOpts: Object.merge(pathOpts, {mongos: i}),
- verbose: mongosVerboseLevel,
- keyFile: this.keyFile,
- };
+ this._connections.push(null);
- if (otherParams.mongosOptions && otherParams.mongosOptions.binVersion) {
- otherParams.mongosOptions.binVersion =
- MongoRunner.versionIterator(otherParams.mongosOptions.binVersion);
- }
+ let rsConn = new Mongo(rs.getURL());
+ rsConn.name = rs.getURL();
- options = Object.merge(options, otherParams.mongosOptions);
- options = Object.merge(options, otherParams["s" + i]);
-
- // The default time for mongos quiesce mode in response to SIGTERM is 15 seconds.
- // Reduce this to 0 for faster shutdown.
- options.setParameter = options.setParameter || {};
- options.setParameter.mongosShutdownTimeoutMillisForSignaledShutdown =
- options.setParameter.mongosShutdownTimeoutMillisForSignaledShutdown || 0;
+ this._connections[i] = rsConn;
+ this["shard" + i] = rsConn;
+ rsConn.rs = rs;
+ }
- options.port = options.port || _allocatePortForMongos();
+ // Wait for master to be elected before starting mongos
+ this.configRS.awaitNodesAgreeOnPrimary();
+ var csrsPrimary = this.configRS.getPrimary();
+
+ print("ShardingTest startup and initiation for all nodes took " + (new Date() - startTime) +
+ "ms with " + this.configRS.nodeList().length + " config server nodes and " +
+ totalNumShardNodes() + " total shard nodes.");
+
+ // If 'otherParams.mongosOptions.binVersion' is an array value, then we'll end up constructing a
+ // version iterator.
+ const mongosOptions = [];
+ for (var i = 0; i < numMongos; ++i) {
+ let options = {
+ useHostname: otherParams.useHostname,
+ pathOpts: Object.merge(pathOpts, {mongos: i}),
+ verbose: mongosVerboseLevel,
+ keyFile: this.keyFile,
+ };
- mongosOptions.push(options);
+ if (otherParams.mongosOptions && otherParams.mongosOptions.binVersion) {
+ otherParams.mongosOptions.binVersion =
+ MongoRunner.versionIterator(otherParams.mongosOptions.binVersion);
}
- const configRS = this.configRS;
- const clusterVersionInfo = this.getClusterVersionInfo();
- if (_hasNewFeatureCompatibilityVersion() && clusterVersionInfo.isMixedVersion) {
- const fcv = binVersionToFCV(clusterVersionInfo.oldestBinVersion);
- function setFeatureCompatibilityVersion() {
- assert.commandWorked(csrsPrimary.adminCommand(
- {setFeatureCompatibilityVersion: fcv, fromConfigServer: true}));
+ options = Object.merge(options, otherParams.mongosOptions);
+ options = Object.merge(options, otherParams["s" + i]);
- // Wait for the new featureCompatibilityVersion to propagate to all nodes in the
- // CSRS to ensure that older versions of mongos can successfully connect.
- configRS.awaitReplication();
- }
+ // The default time for mongos quiesce mode in response to SIGTERM is 15 seconds.
+ // Reduce this to 0 for faster shutdown.
+ options.setParameter = options.setParameter || {};
+ options.setParameter.mongosShutdownTimeoutMillisForSignaledShutdown =
+ options.setParameter.mongosShutdownTimeoutMillisForSignaledShutdown || 0;
- if (this.keyFile) {
- authutil.asCluster(
- this.configRS.nodes, this.keyFile, setFeatureCompatibilityVersion);
- } else {
- setFeatureCompatibilityVersion();
- }
- }
+ options.port = options.port || _allocatePortForMongos();
- // If chunkSize has been requested for this test, write the configuration
- if (otherParams.chunkSize) {
- function setChunkSize() {
- assert.commandWorked(csrsPrimary.getDB('config').settings.update(
- {_id: 'chunksize'},
- {$set: {value: otherParams.chunkSize}},
- {upsert: true, writeConcern: {w: 'majority', wtimeout: kDefaultWTimeoutMs}}));
+ mongosOptions.push(options);
+ }
- configRS.awaitLastOpCommitted();
- }
+ const configRS = this.configRS;
+ const clusterVersionInfo = this.getClusterVersionInfo();
+ if (_hasNewFeatureCompatibilityVersion() && clusterVersionInfo.isMixedVersion) {
+ const fcv = binVersionToFCV(clusterVersionInfo.oldestBinVersion);
+ function setFeatureCompatibilityVersion() {
+ assert.commandWorked(csrsPrimary.adminCommand(
+ {setFeatureCompatibilityVersion: fcv, fromConfigServer: true}));
- if (this.keyFile) {
- authutil.asCluster(csrsPrimary, this.keyFile, setChunkSize);
- } else {
- setChunkSize();
- }
+ // Wait for the new featureCompatibilityVersion to propagate to all nodes in the CSRS
+ // to ensure that older versions of mongos can successfully connect.
+ configRS.awaitReplication();
}
- this._configDB = this.configRS.getURL();
- for (var i = 0; i < numConfigs; ++i) {
- var conn = this.configRS.nodes[i];
- this["config" + i] = conn;
- this["c" + i] = conn;
+ if (this.keyFile) {
+ authutil.asCluster(this.configRS.nodes, this.keyFile, setFeatureCompatibilityVersion);
+ } else {
+ setFeatureCompatibilityVersion();
}
+ }
- printjson('Config servers: ' + this._configDB);
+ // If chunkSize has been requested for this test, write the configuration
+ if (otherParams.chunkSize) {
+ function setChunkSize() {
+ assert.commandWorked(csrsPrimary.getDB('config').settings.update(
+ {_id: 'chunksize'},
+ {$set: {value: otherParams.chunkSize}},
+ {upsert: true, writeConcern: {w: 'majority', wtimeout: kDefaultWTimeoutMs}}));
- print("ShardingTest " + this._testName + " :\n" +
- tojson({config: this._configDB, shards: this._connections}));
+ configRS.awaitLastOpCommitted();
+ }
- this._mongos = [];
+ if (this.keyFile) {
+ authutil.asCluster(csrsPrimary, this.keyFile, setChunkSize);
+ } else {
+ setChunkSize();
+ }
+ }
- // Start the MongoS servers
- for (var i = 0; i < numMongos; i++) {
- const options = mongosOptions[i];
- options.configdb = this._configDB;
+ this._configDB = this.configRS.getURL();
+ for (var i = 0; i < numConfigs; ++i) {
+ var conn = this.configRS.nodes[i];
+ this["config" + i] = conn;
+ this["c" + i] = conn;
+ }
- if (otherParams.useBridge) {
- var bridgeOptions =
- Object.merge(otherParams.bridgeOptions, options.bridgeOptions || {});
- bridgeOptions = Object.merge(bridgeOptions, {
- hostName: otherParams.useHostname ? hostName : "localhost",
- port: _allocatePortForBridgeForMongos(),
- // The mongos processes identify themselves to mongobridge as host:port, where
- // the host is the actual hostname of the machine and not localhost.
- dest: hostName + ":" + options.port,
- });
+ printjson('Config servers: ' + this._configDB);
- var bridge = new MongoBridge(bridgeOptions);
- }
+ print("ShardingTest " + this._testName + " :\n" +
+ tojson({config: this._configDB, shards: this._connections}));
- var conn = MongoRunner.runMongos(options);
- if (!conn) {
- throw new Error("Failed to start mongos " + i);
- }
+ this._mongos = [];
- if (otherParams.causallyConsistent) {
- conn.setCausalConsistency(true);
- }
+ // Start the MongoS servers
+ for (var i = 0; i < numMongos; i++) {
+ const options = mongosOptions[i];
+ options.configdb = this._configDB;
- if (otherParams.useBridge) {
- bridge.connectToBridge();
- this._mongos.push(bridge);
- unbridgedMongos.push(conn);
- } else {
- this._mongos.push(conn);
- }
+ if (otherParams.useBridge) {
+ var bridgeOptions =
+ Object.merge(otherParams.bridgeOptions, options.bridgeOptions || {});
+ bridgeOptions = Object.merge(bridgeOptions, {
+ hostName: otherParams.useHostname ? hostName : "localhost",
+ port: _allocatePortForBridgeForMongos(),
+ // The mongos processes identify themselves to mongobridge as host:port, where the
+ // host is the actual hostname of the machine and not localhost.
+ dest: hostName + ":" + options.port,
+ });
- if (i === 0) {
- this.s = this._mongos[i];
- this.admin = this._mongos[i].getDB('admin');
- this.config = this._mongos[i].getDB('config');
- }
+ var bridge = new MongoBridge(bridgeOptions);
+ }
- this["s" + i] = this._mongos[i];
+ var conn = MongoRunner.runMongos(options);
+ if (!conn) {
+ throw new Error("Failed to start mongos " + i);
}
- _extendWithShMethods();
+ if (otherParams.causallyConsistent) {
+ conn.setCausalConsistency(true);
+ }
- // If auth is enabled for the test, login the mongos connections as system in order to
- // configure the instances and then log them out again.
- if (this.keyFile) {
- authutil.asCluster(this._mongos, this.keyFile, _configureCluster);
- } else if (mongosOptions[0] && mongosOptions[0].keyFile) {
- authutil.asCluster(this._mongos, mongosOptions[0].keyFile, _configureCluster);
+ if (otherParams.useBridge) {
+ bridge.connectToBridge();
+ this._mongos.push(bridge);
+ unbridgedMongos.push(conn);
} else {
- _configureCluster();
- // Ensure that all config server nodes are up to date with any changes made to balancer
- // settings before adding shards to the cluster. This prevents shards, which read
- // config.settings with readPreference 'nearest', from accidentally fetching stale
- // values from secondaries that aren't up-to-date.
- this.configRS.awaitLastOpCommitted();
+ this._mongos.push(conn);
}
- try {
- if (!otherParams.manualAddShard) {
- var testName = this._testName;
- var admin = this.admin;
+ if (i === 0) {
+ this.s = this._mongos[i];
+ this.admin = this._mongos[i].getDB('admin');
+ this.config = this._mongos[i].getDB('config');
+ }
- this._connections.forEach(function(z) {
- var n = z.name || z.host || z;
+ this["s" + i] = this._mongos[i];
+ }
- print("ShardingTest " + testName + " going to add shard : " + n);
+ _extendWithShMethods();
- var result = assert.commandWorked(admin.runCommand({addshard: n}),
- "Failed to add shard " + n);
- z.shardName = result.shardAdded;
- });
- }
- } catch (e) {
- // Clean up the running procceses on failure
- print("Failed to add shards, stopping cluster.");
- this.stop();
- throw e;
- }
-
- // Ensure that the sessions collection exists so jstests can run things with
- // logical sessions and test them. We do this by forcing an immediate cache refresh
- // on the config server, which auto-shards the collection for the cluster.
- this.configRS.getPrimary().getDB("admin").runCommand({refreshLogicalSessionCacheNow: 1});
-
- // Ensure that all CSRS nodes are up to date. This is strictly needed for tests that use
- // multiple mongoses. In those cases, the first mongos initializes the contents of the
- // 'config' database, but without waiting for those writes to replicate to all the config
- // servers then the secondary mongoses risk reading from a stale config server and seeing an
- // empty config database.
+ // If auth is enabled for the test, login the mongos connections as system in order to configure
+ // the instances and then log them out again.
+ if (this.keyFile) {
+ authutil.asCluster(this._mongos, this.keyFile, _configureCluster);
+ } else if (mongosOptions[0] && mongosOptions[0].keyFile) {
+ authutil.asCluster(this._mongos, mongosOptions[0].keyFile, _configureCluster);
+ } else {
+ _configureCluster();
+ // Ensure that all config server nodes are up to date with any changes made to balancer
+ // settings before adding shards to the cluster. This prevents shards, which read
+ // config.settings with readPreference 'nearest', from accidentally fetching stale values
+ // from secondaries that aren't up-to-date.
this.configRS.awaitLastOpCommitted();
+ }
+
+ try {
+ if (!otherParams.manualAddShard) {
+ var testName = this._testName;
+ var admin = this.admin;
+
+ this._connections.forEach(function(z) {
+ var n = z.name || z.host || z;
- if (jsTestOptions().keyFile) {
- jsTest.authenticateNodes(this._mongos);
+ print("ShardingTest " + testName + " going to add shard : " + n);
+
+ var result = assert.commandWorked(admin.runCommand({addshard: n}),
+ "Failed to add shard " + n);
+ z.shardName = result.shardAdded;
+ });
}
+ } catch (e) {
+ // Clean up the running procceses on failure
+ print("Failed to add shards, stopping cluster.");
+ this.stop();
+ throw e;
+ }
- // Flushes the routing table cache on connection 'conn'. If 'keyFileLocal' is defined,
- // authenticates the keyfile user.
- const flushRT = function flushRoutingTableAndHandleAuth(conn, keyFileLocal) {
- // Invokes the actual execution of cache refresh.
- const execFlushRT = (conn) => {
- assert.commandWorked(conn.getDB("admin").runCommand(
- {_flushRoutingTableCacheUpdates: "config.system.sessions"}));
- };
+ // Ensure that the sessions collection exists so jstests can run things with
+ // logical sessions and test them. We do this by forcing an immediate cache refresh
+ // on the config server, which auto-shards the collection for the cluster.
+ this.configRS.getPrimary().getDB("admin").runCommand({refreshLogicalSessionCacheNow: 1});
- const x509AuthRequired = (conn.fullOptions && conn.fullOptions.clusterAuthMode &&
- conn.fullOptions.clusterAuthMode === "x509");
-
- if (keyFileLocal) {
- authutil.asCluster(conn, keyFileLocal, () => execFlushRT(conn));
- } else if (x509AuthRequired) {
- const exitCode =
- _runMongoProgram(...["mongo",
- conn.host,
- "--tls",
- "--tlsAllowInvalidHostnames",
- "--tlsCertificateKeyFile",
- conn.fullOptions.tlsCertificateKeyFile
- ? conn.fullOptions.tlsCertificateKeyFile
- : conn.fullOptions.sslPEMKeyFile,
- "--tlsCAFile",
- conn.fullOptions.tlsCAFile ? conn.fullOptions.tlsCAFile
- : conn.fullOptions.sslCAFile,
- "--authenticationDatabase=$external",
- "--authenticationMechanism=MONGODB-X509",
- "--eval",
- `(${execFlushRT.toString()})(db.getMongo())`,
- ]);
- assert.eq(0, exitCode, "parallel shell for x509 auth failed");
- } else {
- execFlushRT(conn);
- }
- };
+ // Ensure that all CSRS nodes are up to date. This is strictly needed for tests that use
+ // multiple mongoses. In those cases, the first mongos initializes the contents of the 'config'
+ // database, but without waiting for those writes to replicate to all the config servers then
+ // the secondary mongoses risk reading from a stale config server and seeing an empty config
+ // database.
+ this.configRS.awaitLastOpCommitted();
- if (!otherParams.manualAddShard) {
- for (let i = 0; i < numShards; i++) {
- const keyFileLocal =
- (otherParams.shards && otherParams.shards[i] && otherParams.shards[i].keyFile)
- ? otherParams.shards[i].keyFile
- : this.keyFile;
-
- const rs = this._rs[i].test;
- flushRT(rs.getPrimary(), keyFileLocal);
- }
+ if (jsTestOptions().keyFile) {
+ jsTest.authenticateNodes(this._mongos);
+ }
+
+ // Flushes the routing table cache on connection 'conn'. If 'keyFileLocal' is defined,
+ // authenticates the keyfile user.
+ const flushRT = function flushRoutingTableAndHandleAuth(conn, keyFileLocal) {
+ // Invokes the actual execution of cache refresh.
+ const execFlushRT = (conn) => {
+ assert.commandWorked(conn.getDB("admin").runCommand(
+ {_flushRoutingTableCacheUpdates: "config.system.sessions"}));
+ };
- self.waitForShardingInitialized();
+ const x509AuthRequired = (conn.fullOptions && conn.fullOptions.clusterAuthMode &&
+ conn.fullOptions.clusterAuthMode === "x509");
+
+ if (keyFileLocal) {
+ authutil.asCluster(conn, keyFileLocal, () => execFlushRT(conn));
+ } else if (x509AuthRequired) {
+ const exitCode = _runMongoProgram(
+ ...["mongo",
+ conn.host,
+ "--tls",
+ "--tlsAllowInvalidHostnames",
+ "--tlsCertificateKeyFile",
+ conn.fullOptions.tlsCertificateKeyFile ? conn.fullOptions.tlsCertificateKeyFile
+ : conn.fullOptions.sslPEMKeyFile,
+ "--tlsCAFile",
+ conn.fullOptions.tlsCAFile ? conn.fullOptions.tlsCAFile
+ : conn.fullOptions.sslCAFile,
+ "--authenticationDatabase=$external",
+ "--authenticationMechanism=MONGODB-X509",
+ "--eval",
+ `(${execFlushRT.toString()})(db.getMongo())`,
+ ]);
+ assert.eq(0, exitCode, "parallel shell for x509 auth failed");
+ } else {
+ execFlushRT(conn);
}
- } catch (e) {
- // this was expected to fail, so clean up appropriately
- if (params.shouldFailInit === true) {
- this.stopOnFail();
+ };
+
+ if (!otherParams.manualAddShard) {
+ for (let i = 0; i < numShards; i++) {
+ const keyFileLocal =
+ (otherParams.shards && otherParams.shards[i] && otherParams.shards[i].keyFile)
+ ? otherParams.shards[i].keyFile
+ : this.keyFile;
+
+ const rs = this._rs[i].test;
+ flushRT(rs.getPrimary(), keyFileLocal);
}
- throw e;
+
+ self.waitForShardingInitialized();
}
- // This initialization was expected to fail, but it did not.
- assert.neq(
- true, params.shouldFailInit, "This was expected to fail initialization, but it did not");
};
// Stub for a hook to check that collection UUIDs are consistent across shards and the config
diff --git a/src/mongo/shell/shell_utils.cpp b/src/mongo/shell/shell_utils.cpp
index abdbb179bfa..cb82f223f9b 100644
--- a/src/mongo/shell/shell_utils.cpp
+++ b/src/mongo/shell/shell_utils.cpp
@@ -521,23 +521,15 @@ BSONObj numberDecimalsAlmostEqual(const BSONObj& input, void*) {
auto ten = Decimal128(10);
auto exponent = a.toAbs().logarithm(ten).round();
- // Early exit for zero, infinity and NaN cases.
- if ((a.isZero() && b.isZero()) || (a.isNaN() && b.isNaN()) ||
- (a.isInfinite() && b.isInfinite() && (a.isNegative() == b.isNegative()))) {
- return BSON("" << true /* isErrorAcceptable */);
- } else if (!a.isZero() && !b.isZero()) {
- // Return early if arguments are not the same order of magnitude.
- if (exponent != b.toAbs().logarithm(ten).round()) {
- return BSON("" << false);
- }
-
- // Put the whole number behind the decimal point.
- if (!exponent.isZero()) {
- a = a.divide(ten.power(exponent));
- b = b.divide(ten.power(exponent));
- }
+ // Return early if arguments are not the same order of magnitude.
+ if (exponent != b.toAbs().logarithm(ten).round()) {
+ return BSON("" << false);
}
+ // Put the whole number behind the decimal point.
+ a = a.divide(ten.power(exponent));
+ b = b.divide(ten.power(exponent));
+
auto places = third.numberDecimal();
auto isErrorAcceptable = a.subtract(b)
.toAbs()
diff --git a/src/mongo/shell/types.js b/src/mongo/shell/types.js
index ce8fd02b172..c06601f9161 100644
--- a/src/mongo/shell/types.js
+++ b/src/mongo/shell/types.js
@@ -292,36 +292,6 @@ Object.merge = function(dst, src, deep) {
return Object.extend(clone, src, deep);
};
-// If there is a conflict in values of a key for two objects being merged, the second value will
-// override the first one in the merged object
-Object.deepMerge = function(...objects) {
- const isObject = obj => obj && typeof obj === 'object';
-
- // Create new object prev to hold combination of all object fields.
- return objects.reduce((prev, obj) => {
- if (obj === undefined) {
- obj = {};
- }
- Object.keys(obj).forEach(key => {
- const pVal = prev[key]; // Get the values for key from the two objects being merged.
- const oVal = obj[key];
-
- if (Array.isArray(pVal) &&
- Array.isArray(oVal)) { // If both are arrays then concatenate them into a new
- // array and add it to prev.
- prev[key] = pVal.concat(...oVal);
- } else if (isObject(pVal) &&
- isObject(oVal)) { // If both are objects then recursively merge again.
- prev[key] = Object.deepMerge(pVal, oVal);
- } else { // In all other cases set prev[key] to obj[key].
- prev[key] = oVal;
- }
- });
-
- return prev;
- }, {});
-};
-
Object.keySet = function(o) {
var ret = new Array();
for (var i in o) {
diff --git a/src/mongo/shell/utils.js b/src/mongo/shell/utils.js
index e1e09a83a7b..ebfa03f7268 100644
--- a/src/mongo/shell/utils.js
+++ b/src/mongo/shell/utils.js
@@ -29,13 +29,6 @@ function _getErrorWithCode(codeOrObj, message) {
if (codeOrObj.hasOwnProperty("writeErrors")) {
e.writeErrors = codeOrObj.writeErrors;
- } else if ((codeOrObj instanceof BulkWriteResult || codeOrObj instanceof BulkWriteError) &&
- codeOrObj.hasWriteErrors()) {
- e.writeErrors = codeOrObj.getWriteErrors();
- }
-
- if (codeOrObj instanceof WriteResult && codeOrObj.hasWriteError()) {
- e.writeErrors = [codeOrObj.getWriteError()];
}
if (codeOrObj.hasOwnProperty("errorLabels")) {
@@ -92,11 +85,7 @@ function isNetworkError(errorOrResponse) {
"error doing query",
"socket exception",
"SocketException",
- "HostNotFound",
- "HostUnreachable",
- "NetworkTimeout",
- "ConnectionPoolExpired",
- "ConnectionError"
+ "HostNotFound"
];
// Then check if it's an Error, if so see if any of the known network error strings appear
@@ -1141,6 +1130,52 @@ shellHelper.show = function(what) {
}
}
+ if (what == "freeMonitoring") {
+ var dbDeclared, ex;
+ try {
+ // !!db essentially casts db to a boolean
+ // Will throw a reference exception if db hasn't been declared.
+ dbDeclared = !!db;
+ } catch (ex) {
+ dbDeclared = false;
+ }
+
+ if (dbDeclared) {
+ const freemonStatus = db.adminCommand({getFreeMonitoringStatus: 1});
+
+ if (freemonStatus.ok) {
+ if (freemonStatus.state == 'enabled' &&
+ freemonStatus.hasOwnProperty('userReminder')) {
+ print("---");
+ print(freemonStatus.userReminder);
+ print("---");
+ } else if (freemonStatus.state === 'undecided') {
+ print(
+ "---\n" + messageIndent +
+ "Enable MongoDB's free cloud-based monitoring service, which will then receive and display\n" +
+ messageIndent +
+ "metrics about your deployment (disk utilization, CPU, operation statistics, etc).\n" +
+ "\n" + messageIndent +
+ "The monitoring data will be available on a MongoDB website with a unique URL accessible to you\n" +
+ messageIndent +
+ "and anyone you share the URL with. MongoDB may use this information to make product\n" +
+ messageIndent +
+ "improvements and to suggest MongoDB products and deployment options to you.\n" +
+ "\n" + messageIndent +
+ "To enable free monitoring, run the following command: db.enableFreeMonitoring()\n" +
+ messageIndent +
+ "To permanently disable this reminder, run the following command: db.disableFreeMonitoring()\n" +
+ "---\n");
+ }
+ }
+
+ return "";
+ } else {
+ print("Cannot show freeMonitoring, \"db\" is not set");
+ return "";
+ }
+ }
+
if (what == "nonGenuineMongoDBCheck") {
let matchesKnownImposterSignature = false;
diff --git a/src/mongo/shell/utils_sh.js b/src/mongo/shell/utils_sh.js
index e086bbf8f46..b4bd7175096 100644
--- a/src/mongo/shell/utils_sh.js
+++ b/src/mongo/shell/utils_sh.js
@@ -96,9 +96,6 @@ sh.help = function() {
"returns wheter the specified collection is balanced or the balancer needs to take more actions on it");
print("\tsh.configureCollectionBalancing(fullName, params) " +
"configure balancing settings for a specific collection");
- print("\tsh.awaitCollectionBalance(coll) waits for a collection to be balanced");
- print(
- "\tsh.verifyCollectionIsBalanced(coll) verifies that a collection is well balanced by checking the actual data size on each shard");
};
sh.status = function(verbose, configDB) {
@@ -258,28 +255,18 @@ sh.waitForPingChange = function(activePings, timeout, interval) {
return remainingPings;
};
-/**
- * Waits up to the specified timeout (with a default of 60s) for the balancer to execute one
- * round. If no round has been executed, throws an error.
- */
-sh.awaitBalancerRound = function(timeout, interval) {
- timeout = timeout || 60000;
-
+sh.waitForBalancer = function(wait, timeout, interval) {
+ if (typeof (wait) === 'undefined') {
+ wait = false;
+ }
var initialStatus = sh._getBalancerStatus();
+ if (!initialStatus.inBalancerRound && !wait) {
+ return;
+ }
var currentStatus;
assert.soon(function() {
currentStatus = sh._getBalancerStatus();
- assert.eq(currentStatus.mode, 'full', "Balancer is disabled");
- if (!friendlyEqual(currentStatus.term, initialStatus.term)) {
- // A new primary of the csrs has been elected
- initialStatus = currentStatus;
- return false;
- }
- assert.gte(currentStatus.numBalancerRounds,
- initialStatus.numBalancerRounds,
- 'Number of balancer rounds moved back in time unexpectedly. Current status: ' +
- tojson(currentStatus) + ', initial status: ' + tojson(initialStatus));
- return currentStatus.numBalancerRounds > initialStatus.numBalancerRounds;
+ return (currentStatus.numBalancerRounds - initialStatus.numBalancerRounds) != 0;
}, 'Latest balancer status: ' + tojson(currentStatus), timeout, interval);
};
@@ -317,118 +304,6 @@ sh.enableBalancing = function(coll) {
{writeConcern: {w: 'majority', wtimeout: 60000}}));
};
-sh.awaitCollectionBalance = function(coll, timeout, interval) {
- if (coll === undefined) {
- throw Error("Must specify collection");
- }
- timeout = timeout || 60000;
- interval = interval || 200;
-
- const ns = coll.getFullName();
- const orphanDocsPipeline = [
- {'$collStats': {'storageStats': {}}},
- {'$project': {'shard': true, 'storageStats': {'numOrphanDocs': true}}},
- {'$group': {'_id': null, 'totalNumOrphanDocs': {'$sum': '$storageStats.numOrphanDocs'}}}
- ];
-
- var oldDb = (typeof (db) === 'undefined' ? undefined : db);
- try {
- db = coll.getDB();
-
- assert.soon(
- function() {
- assert.soon(function() {
- return assert
- .commandWorked(sh._adminCommand({balancerCollectionStatus: ns}, true))
- .balancerCompliant;
- }, 'Timed out waiting for the collection to be balanced', timeout, interval);
-
- // (SERVER-67301) Wait for orphans counter to be 0 to account for potential stale
- // orphans count
- sh.disableBalancing(coll);
- assert.soon(function() {
- return coll.aggregate(orphanDocsPipeline).toArray()[0].totalNumOrphanDocs === 0;
- }, 'Timed out waiting for orphans counter to be 0', timeout, interval);
- sh.enableBalancing(coll);
-
- // (SERVER-70602) Wait for some balancing rounds to avoid balancerCollectionStatus
- // reporting balancerCompliant too early
- for (let i = 0; i < 3; ++i) {
- sh.awaitBalancerRound(timeout, interval);
- }
-
- return assert.commandWorked(sh._adminCommand({balancerCollectionStatus: ns}, true))
- .balancerCompliant;
- },
- 'Timed out waiting for collection to be balanced and orphans counter to be 0',
- timeout,
- interval);
- } finally {
- db = oldDb;
- }
-};
-
-/**
- * Verifies if given collection is properly balanced according to the data size aware balancing
- * policy
- */
-sh.verifyCollectionIsBalanced = function(coll) {
- if (coll === undefined) {
- throw Error("Must specify collection");
- }
-
- var oldDb = db;
- try {
- db = coll.getDB();
-
- const configDB = sh._getConfigDB();
- const ns = coll.getFullName();
- const collection = configDB.collections.findOne({_id: ns});
-
- let collSizeOnShards = [];
- let shards = [];
- const collStatsPipeline = [
- {'$collStats': {'storageStats': {}}},
- {
- '$project': {
- 'shard': true,
- 'storageStats':
- {'count': true, 'size': true, 'avgObjSize': true, 'numOrphanDocs': true}
- }
- },
- {'$sort': {'shard': 1}}
- ];
-
- let kChunkSize = 1024 * 1024 *
- assert.commandWorked(sh._adminCommand({balancerCollectionStatus: ns})).chunkSize;
- // TODO SERVER-67898 delete kChunkSize overwrite after completing the ticket
- if (kChunkSize == 0) {
- kChunkSize = collection.maxChunkSizeBytes;
- }
-
- // Get coll size per shard
- const storageStats = coll.aggregate(collStatsPipeline).toArray();
- coll.aggregate(collStatsPipeline).forEach((shardStats) => {
- shards.push(shardStats['shard']);
- const collSize = (shardStats['storageStats']['count'] -
- shardStats['storageStats']['numOrphanDocs']) *
- shardStats['storageStats']['avgObjSize'];
- collSizeOnShards.push(collSize);
- });
-
- let errorMsg = "Collection not balanced. collection= " + tojson(collection) +
- ", shards= " + tojson(shards) + ", collSizeOnShards=" + tojson(collSizeOnShards) +
- ", storageStats=" + tojson(storageStats) + ", kChunkSize=" + tojson(kChunkSize);
-
- assert.lte((Math.max(...collSizeOnShards) - Math.min(...collSizeOnShards)),
- 3 * kChunkSize,
- errorMsg);
-
- } finally {
- db = oldDb;
- }
-};
-
/*
* Can call _lastMigration( coll ), _lastMigration( db ), _lastMigration( st ), _lastMigration(
* mongos )