diff options
author | Xiangyu Yao <xiangyu.yao@mongodb.com> | 2018-08-23 15:54:59 -0400 |
---|---|---|
committer | Xiangyu Yao <xiangyu.yao@mongodb.com> | 2018-10-05 16:10:38 -0400 |
commit | 13e13e9ba8a720b0ee95b70c62e59a712af52ac8 (patch) | |
tree | 1a9ed6fcae2a44979913e40fd4011b4a59f40ddb | |
parent | 5849932e9f4ce4c2bef9046fbaa21f3465e3d1eb (diff) | |
download | mongo-13e13e9ba8a720b0ee95b70c62e59a712af52ac8.tar.gz |
SERVER-36718 Add forceValidationWithFeatureCompatibilityVersion to collection validation hook
(cherry picked from commit bdb7951bc48accda8368f5893bdf2627fc2588bf)
-rw-r--r-- | jstests/hooks/run_validate_collections.js | 58 | ||||
-rw-r--r-- | jstests/hooks/validate_collections.js | 54 | ||||
-rw-r--r-- | jstests/libs/discover_topology.js | 34 |
3 files changed, 88 insertions, 58 deletions
diff --git a/jstests/hooks/run_validate_collections.js b/jstests/hooks/run_validate_collections.js index 525003148e1..e0292740b97 100644 --- a/jstests/hooks/run_validate_collections.js +++ b/jstests/hooks/run_validate_collections.js @@ -10,11 +10,14 @@ const topology = DiscoverTopology.findConnectedNodes(db.getMongo()); const hostList = []; + let setFCVHost; if (topology.type === Topology.kStandalone) { hostList.push(topology.mongod); + setFCVHost = topology.mongod; } else if (topology.type === Topology.kReplicaSet) { hostList.push(...topology.nodes); + setFCVHost = topology.primary; } else if (topology.type === Topology.kShardedCluster) { hostList.push(...topology.configsvr.nodes); @@ -29,6 +32,8 @@ throw new Error('Unrecognized topology format: ' + tojson(topology)); } } + // Any of the mongos instances can be used for setting FCV. + setFCVHost = topology.mongos.nodes[0]; } else { throw new Error('Unrecognized topology format: ' + tojson(topology)); } @@ -44,6 +49,18 @@ conn.setSlaveOk(); jsTest.authenticate(conn); + if (jsTest.options().forceValidationWithFeatureCompatibilityVersion) { + let adminDB = conn.getDB('admin'); + // Make sure this node has the desired FCV. + assert.soon(() => { + const res = + adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}); + return res !== null && + res.version === + jsTest.options().forceValidationWithFeatureCompatibilityVersion; + }); + } + const dbNames = conn.getDBNames(); for (let dbName of dbNames) { if (!validateCollections(conn.getDB(dbName), {full: true})) { @@ -61,6 +78,43 @@ // We run the scoped threads in a try/finally block in case any thread throws an exception, in // which case we want to still join all the threads. let threads = []; + let adminDB; + let originalFCV; + + function getFeatureCompatibilityVersion(adminDB) { + const res = adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}); + if (res === null) { + return "3.2"; + } + return res.version; + } + + if (jsTest.options().forceValidationWithFeatureCompatibilityVersion) { + let conn = new Mongo(setFCVHost); + adminDB = conn.getDB('admin'); + try { + originalFCV = getFeatureCompatibilityVersion(adminDB); + } catch (e) { + if (jsTest.options().skipValidationOnInvalidViewDefinitions && + e.code === ErrorCodes.InvalidViewDefinition) { + print("Reading the featureCompatibilityVersion from the admin.system.version" + + " collection failed due to an invalid view definition on the admin database"); + // The view catalog would only have been resolved if the namespace doesn't exist as + // a collection. The absence of the admin.system.version collection is equivalent to + // having featureCompatibilityVersion=3.2. + originalFCV = "3.2"; + } else { + throw e; + } + } + + if (originalFCV !== jsTest.options().forceValidationWithFeatureCompatibilityVersion) { + assert.commandWorked(adminDB.adminCommand({ + setFeatureCompatibilityVersion: + jsTest.options().forceValidationWithFeatureCompatibilityVersion + })); + } + } try { hostList.forEach(host => { @@ -79,4 +133,8 @@ assert.commandWorked(res, 'Collection validation failed'); }); } + + if (jsTest.options().forceValidationWithFeatureCompatibilityVersion !== originalFCV) { + assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: originalFCV})); + } })(); diff --git a/jstests/hooks/validate_collections.js b/jstests/hooks/validate_collections.js index c5be1a230e8..8287388b6c9 100644 --- a/jstests/hooks/validate_collections.js +++ b/jstests/hooks/validate_collections.js @@ -13,19 +13,6 @@ function validateCollections(db, obj) { } } - function getFeatureCompatibilityVersion(adminDB) { - var res = adminDB.system.version.findOne({_id: "featureCompatibilityVersion"}); - if (res === null) { - return "3.2"; - } - return res.version; - } - - function setFeatureCompatibilityVersion(adminDB, version) { - assert.commandWorked(adminDB.runCommand({setFeatureCompatibilityVersion: version})); - assert.eq(version, getFeatureCompatibilityVersion(adminDB)); - } - assert.eq(typeof db, 'object', 'Invalid `db` object, is the shell connected to a mongod?'); assert.eq(typeof obj, 'object', 'The `obj` argument must be an object'); assert(obj.hasOwnProperty('full'), 'Please specify whether to use full validation'); @@ -34,42 +21,6 @@ function validateCollections(db, obj) { var success = true; - var adminDB = db.getSiblingDB("admin"); - - // Set the featureCompatibilityVersion to its required value for performing validation. Save the - // original value. - var originalFeatureCompatibilityVersion; - if (jsTest.options().forceValidationWithFeatureCompatibilityVersion) { - try { - originalFeatureCompatibilityVersion = getFeatureCompatibilityVersion(adminDB); - } catch (e) { - if (jsTest.options().skipValidationOnInvalidViewDefinitions && - e.code === ErrorCodes.InvalidViewDefinition) { - print("Reading the featureCompatibilityVersion from the admin.system.version" + - " collection failed due to an invalid view definition on the admin database"); - // The view catalog would only have been resolved if the namespace doesn't exist as - // a collection. The absence of the admin.system.version collection is equivalent to - // having featureCompatibilityVersion=3.2. - originalFeatureCompatibilityVersion = "3.2"; - } else { - throw e; - } - } - - try { - setFeatureCompatibilityVersion( - adminDB, jsTest.options().forceValidationWithFeatureCompatibilityVersion); - } catch (e) { - if (e.code === ErrorCodes.NotMaster) { - print('Skipping collection validation on ' + db.getMongo() + ' because the' + - ' featureCompatibilityVersion cannot be changed while connected to a' + - ' secondary'); - return true; - } - throw e; - } - } - // Don't run validate on view namespaces. let filter = {type: "collection"}; if (jsTest.options().skipValidationOnInvalidViewDefinitions) { @@ -108,10 +59,5 @@ function validateCollections(db, obj) { } } - // Restore the original value for featureCompatibilityVersion. - if (jsTest.options().forceValidationWithFeatureCompatibilityVersion) { - setFeatureCompatibilityVersion(adminDB, originalFeatureCompatibilityVersion); - } - return success; } diff --git a/jstests/libs/discover_topology.js b/jstests/libs/discover_topology.js index 95b072894b0..175f5831eaf 100644 --- a/jstests/libs/discover_topology.js +++ b/jstests/libs/discover_topology.js @@ -4,6 +4,7 @@ // Symbol type, so we just use unique string values instead. var Topology = { kStandalone: 'stand-alone', + kRouter: 'mongos router', kReplicaSet: 'replica set', kShardedCluster: 'sharded cluster', }; @@ -22,7 +23,11 @@ var DiscoverTopology = (function() { // The "passives" field contains the list of unelectable (priority=0) secondaries // and is omitted from the server's response when there are none. res.passives = res.passives || []; - return {type: Topology.kReplicaSet, nodes: [...res.hosts, ...res.passives]}; + return { + type: Topology.kReplicaSet, + primary: res.primary, + nodes: [...res.hosts, ...res.passives] + }; } function findConnectedNodesViaMongos(conn, options) { @@ -58,7 +63,22 @@ var DiscoverTopology = (function() { shardHosts[shardInfo._id] = getDataMemberConnectionStrings(shardConn); } - return {type: Topology.kShardedCluster, configsvr: configsvrHosts, shards: shardHosts}; + // Discover mongos URIs from the connection string. If a mongos is not passed in explicitly, + // it will not be discovered. Prior to the changes from SERVER-28560 and SERVER-31061, only + // one mongos URI could be present in the connection string. + const mongosUris = new MongoURI("mongodb://" + conn.host); + + const mongos = { + type: Topology.kRouter, + nodes: mongosUris.servers.map(uriObj => uriObj.server), + }; + + return { + type: Topology.kShardedCluster, + configsvr: configsvrHosts, + shards: shardHosts, + mongos: mongos, + }; } return { @@ -72,7 +92,11 @@ var DiscoverTopology = (function() { * is returned. * * For a replica set, an object of the form - * {type: Topology.kReplicaSet, nodes: [<conn-string1>, <conn-string2>, ...]} + * { + * type: Topology.kReplicaSet, + * primary: <primary-conn-string>, + * nodes: [<conn-string1>, <conn-string2>, ...], + * } * is returned. * * For a sharded cluster, an object of the form @@ -81,7 +105,9 @@ var DiscoverTopology = (function() { * configsvr: {nodes: [...]}, * shards: { * <shard-name1>: {type: Topology.kStandalone, mongod: ...}, - * <shard-name2>: {type: Topology.kReplicaSet, nodes: [...]}, + * <shard-name2>: {type: Topology.kReplicaSet, + * primary: <primary-conn-string>, + * nodes: [...]}, * ... * } * } |