diff options
19 files changed, 264 insertions, 1668 deletions
diff --git a/buildscripts/resmokeconfig/suites/concurrency_sharded_with_stepdowns.yml b/buildscripts/resmokeconfig/suites/concurrency_sharded_with_stepdowns.yml index acafd931353..ce3749db4bd 100644 --- a/buildscripts/resmokeconfig/suites/concurrency_sharded_with_stepdowns.yml +++ b/buildscripts/resmokeconfig/suites/concurrency_sharded_with_stepdowns.yml @@ -169,9 +169,6 @@ selector: - jstests/concurrency/fsm_workloads/snapshot_read_kill_op_only.js - jstests/concurrency/fsm_workloads/snapshot_read_kill_operations.js - # Expects same CSRS primary and shard primary throughout the test - - jstests/sharding/mongos_forwards_api_parameters_to_shards.js - exclude_with_any_tags: - requires_replication - requires_non_retryable_writes diff --git a/buildscripts/resmokeconfig/suites/sharding_continuous_config_stepdown.yml b/buildscripts/resmokeconfig/suites/sharding_continuous_config_stepdown.yml index 03e804ced4f..d6c78268669 100644 --- a/buildscripts/resmokeconfig/suites/sharding_continuous_config_stepdown.yml +++ b/buildscripts/resmokeconfig/suites/sharding_continuous_config_stepdown.yml @@ -221,9 +221,6 @@ selector: - jstests/sharding/conversion_of_replica_set_to_sharded_cluster.js - jstests/sharding/move_primary_with_writes.js - # Expects same CSRS primary and shard primary throughout the test - - jstests/sharding/mongos_forwards_api_parameters_to_shards.js - executor: config: shell_options: diff --git a/jstests/sharding/api_params_nontransaction_sharded.js b/jstests/sharding/api_params_nontransaction_sharded.js deleted file mode 100644 index 0744f38be96..00000000000 --- a/jstests/sharding/api_params_nontransaction_sharded.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * When a client calls a mongos command with API parameters, mongos must forward them to shards. - * - * @tags: [multiversion_incompatible] - */ - -(function() { -'use strict'; - -load('jstests/sharding/libs/mongos_api_params_util.js'); -MongosAPIParametersUtil.runTests({inTransaction: false, shardedCollection: true}); -})(); diff --git a/jstests/sharding/api_params_nontransaction_unsharded.js b/jstests/sharding/api_params_nontransaction_unsharded.js deleted file mode 100644 index d9eb64570cd..00000000000 --- a/jstests/sharding/api_params_nontransaction_unsharded.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * When a client calls a mongos command with API parameters, mongos must forward them to shards. - * - * @tags: [multiversion_incompatible] - */ - -(function() { -'use strict'; - -load('jstests/sharding/libs/mongos_api_params_util.js'); -MongosAPIParametersUtil.runTests({inTransaction: false, shardedCollection: false}); -})(); diff --git a/jstests/sharding/api_params_transaction_sharded.js b/jstests/sharding/api_params_transaction_sharded.js deleted file mode 100644 index 24d88079182..00000000000 --- a/jstests/sharding/api_params_transaction_sharded.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * When a client calls a mongos command with API parameters, mongos must forward them to shards. - * - * @tags: [multiversion_incompatible] - */ - -(function() { -'use strict'; - -load('jstests/sharding/libs/mongos_api_params_util.js'); -MongosAPIParametersUtil.runTests({inTransaction: true, shardedCollection: true}); -})(); diff --git a/jstests/sharding/api_params_transaction_unsharded.js b/jstests/sharding/api_params_transaction_unsharded.js deleted file mode 100644 index c171c10d920..00000000000 --- a/jstests/sharding/api_params_transaction_unsharded.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * When a client calls a mongos command with API parameters, mongos must forward them to shards. - * - * @tags: [multiversion_incompatible] - */ - -(function() { -'use strict'; - -load('jstests/sharding/libs/mongos_api_params_util.js'); -MongosAPIParametersUtil.runTests({inTransaction: true, shardedCollection: false}); -})(); diff --git a/jstests/sharding/libs/mongos_api_params_util.js b/jstests/sharding/libs/mongos_api_params_util.js deleted file mode 100644 index 1da16ff8d52..00000000000 --- a/jstests/sharding/libs/mongos_api_params_util.js +++ /dev/null @@ -1,1496 +0,0 @@ -/* - * Utilities for checking that mongos commands forward their API version parameters to config - * servers and shards. - */ - -let MongosAPIParametersUtil = (function() { - 'use strict'; - - load('jstests/replsets/rslib.js'); - load('jstests/sharding/libs/last_lts_mongos_commands.js'); - load('jstests/sharding/libs/sharded_transactions_helpers.js'); - - function validateTestCase(testCase) { - assert(testCase.skip || testCase.run, - "must specify exactly one of 'skip' or 'run' for test case " + tojson(testCase)); - - if (testCase.skip) { - for (let key of Object.keys(testCase)) { - assert( - key === "commandName" || key === "skip" || key === "conditional", - `if a test case specifies 'skip', it must not specify any other fields besides` + - ` 'commandName' and 'conditional': ${key}: ${tojson(testCase)}`); - } - return; - } - - validateCommandTestCase(testCase.run); - - if (testCase.explain) { - validateCommandTestCase(testCase.explain); - } - } - - function validateCommandTestCase(testCase) { - assert(testCase.command, "must specify 'command' for test case " + tojson(testCase)); - - // Check that required fields are present. - assert(testCase.hasOwnProperty("inAPIVersion1"), - "must specify 'inAPIVersion1' for test case " + tojson(testCase)); - - // Check that all present fields are of the correct type. - assert(typeof (testCase.command) === "function"); - assert(typeof (testCase.inAPIVersion1) === "boolean"); - - for (const [propertyName, defaultValue] of [["runsAgainstAdminDb", false], - ["permittedInTxn", true], - ["permittedOnShardedCollection", true], - ["requiresShardedCollection", false]]) { - if (testCase.hasOwnProperty(propertyName)) { - assert(typeof testCase[propertyName] === "boolean", - `${propertyName} must be a boolean: ${tojson(testCase)}`); - } else { - testCase[propertyName] = defaultValue; - } - } - - assert(testCase.shardCommandName ? typeof (testCase.shardCommandName) === "string" : true); - assert(testCase.configServerCommandName - ? typeof (testCase.configServerCommandName) === "string" - : true); - assert(testCase.shardCommandName || testCase.configServerCommandName, - "must specify shardCommandName and/or configServerCommandName: " + tojson(testCase)); - assert(testCase.setUp ? typeof (testCase.setUp) === "function" : true, - "setUp must be a function: " + tojson(testCase)); - assert(testCase.cleanUp ? typeof (testCase.cleanUp) === "function" : true, - "cleanUp must be a function: " + tojson(testCase)); - } - - function awaitRemoveShard(shardName) { - assert.commandWorked(st.startBalancer()); - st.waitForBalancer(true, 60000); - assert.soon(() => { - const res = st.s.adminCommand({removeShard: shardName}); - jsTestLog(`removeShard result: ${tojson(res)}`); - if (!res.ok && res.code === ErrorCodes.ShardNotFound) { - return true; - } - - return 'completed' === res.state; - }, "removeShard never completed for shard " + shardName, 10 * 60 * 1000, 1000); - assert.commandWorked(st.stopBalancer()); - } - - // Each test case is potentially run with any combination of API parameters, in - // sharded/unsharded collection, inside or outside of a multi-document transaction. The "db" - // database is dropped and recreated between test cases, so most tests don't need custom setUp - // or cleanUp. Test cases are not 1-1 with commands, e.g. "count" has two cases. - let testCases = [ - { - commandName: "_hashBSONElement", - skip: "executes locally on mongos (not sent to any remote node)" - }, - {commandName: "_isSelf", skip: "executes locally on mongos (not sent to any remote node)"}, - { - commandName: "_killOperations", - skip: "executes locally on mongos (not sent to any remote node)" - }, - {commandName: "_mergeAuthzCollections", skip: "internal API"}, - {commandName: "abortTransaction", skip: "prohibits API parameters"}, - { - commandName: "addShard", - run: { - inAPIVersion1: false, - runsAgainstAdminDb: true, - configServerCommandName: "_configsvrAddShard", - shardCommandName: "_addShard", - permittedInTxn: false, - setUp: () => { - // Remove shard0 so we can add it back. - assert.commandWorked(st.s0.getDB("db").dropDatabase()); - awaitRemoveShard(st.shard0.shardName); - }, - command: () => ({addShard: st.rs0.getURL()}) - } - }, - { - commandName: "addShardToZone", - run: { - inAPIVersion1: false, - runsAgainstAdminDb: true, - configServerCommandName: "_configsvrAddShardToZone", - permittedInTxn: false, - command: () => ({addShardToZone: st.shard0.shardName, zone: "foo"}), - cleanUp: () => assert.commandWorked(st.s0.getDB("admin").runCommand( - {removeShardFromZone: st.shard0.shardName, zone: "foo"})) - } - }, - { - commandName: "aggregate", - run: { - inAPIVersion1: true, - shardCommandName: "aggregate", - command: () => ({aggregate: "collection", pipeline: [], cursor: {}}) - }, - explain: { - inAPIVersion1: true, - shardCommandName: "explain", - permittedInTxn: false, - command: () => ({explain: {aggregate: "collection", pipeline: [], cursor: {}}}) - } - }, - { - commandName: "authenticate", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "availableQueryOptions", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "balancerCollectionStatus", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "balancerStart", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "balancerStatus", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "balancerStop", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "buildInfo", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "clearJumboFlag", - skip: "executes locally on mongos (not sent to any remote node)" - }, - {commandName: "clearLog", skip: "executes locally on mongos (not sent to any remote node)"}, - { - commandName: "collMod", - run: { - inAPIVersion1: true, - shardCommandName: "collMod", - permittedInTxn: false, - command: () => ({collMod: "collection"}), - } - }, - { - commandName: "collStats", - run: { - inAPIVersion1: false, - shardCommandName: "collStats", - permittedInTxn: false, - command: () => ({collStats: "collection"}), - } - }, - {commandName: "commitTransaction", skip: "prohibits API parameters"}, - {commandName: "compact", skip: "not allowed through mongos"}, - { - commandName: "configureFailPoint", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "connPoolStats", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "connPoolSync", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "connectionStatus", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "convertToCapped", - run: { - inAPIVersion1: false, - shardCommandName: "convertToCapped", - permittedOnShardedCollection: false, - permittedInTxn: false, - command: () => ({convertToCapped: "collection", size: 8192}), - } - }, - // The count command behaves differently if it has a query or no query. - { - commandName: "count", - run: { - inAPIVersion1: true, - shardCommandName: "count", - permittedInTxn: false, - command: () => ({count: "collection"}) - }, - explain: { - inAPIVersion1: true, - shardCommandName: "explain", - permittedInTxn: false, - command: () => ({explain: {count: "collection"}}) - } - }, - { - commandName: "count", - run: { - inAPIVersion1: true, - shardCommandName: "count", - permittedInTxn: false, - command: () => ({count: "collection", query: {x: 1}}) - }, - explain: { - inAPIVersion1: true, - shardCommandName: "explain", - permittedInTxn: false, - command: () => ({explain: {count: "collection", query: {x: 1}}}) - } - }, - { - commandName: "create", - run: { - inAPIVersion1: true, - shardCommandName: "create", - command: () => ({create: "collection2"}) - } - }, - { - commandName: "createIndexes", - run: { - inAPIVersion1: true, - shardCommandName: "createIndexes", - permittedInTxn: false, - command: () => - ({createIndexes: "collection", indexes: [{key: {a: 1}, name: "index"}]}) - } - }, - { - commandName: "createRole", - run: { - inAPIVersion1: false, - configServerCommandName: "createRole", - permittedInTxn: false, - command: () => ({createRole: "foo", privileges: [], roles: []}), - cleanUp: () => assert.commandWorked(st.s0.getDB("db").runCommand({dropRole: "foo"})) - } - }, - { - commandName: "createUser", - run: { - inAPIVersion1: false, - configServerCommandName: "createUser", - permittedInTxn: false, - command: () => ({createUser: "foo", pwd: "bar", roles: []}), - cleanUp: () => assert.commandWorked(st.s0.getDB("db").runCommand({dropUser: "foo"})) - } - }, - { - commandName: "currentOp", - run: { - inAPIVersion1: false, - shardCommandName: "aggregate", - permittedInTxn: false, - runsAgainstAdminDb: true, - command: () => ({currentOp: 1}) - } - }, - { - commandName: "dataSize", - run: { - inAPIVersion1: false, - shardCommandName: "dataSize", - permittedInTxn: false, - command: () => ({dataSize: "db.collection"}), - } - }, - { - commandName: "dbStats", - run: { - inAPIVersion1: false, - shardCommandName: "dbStats", - permittedInTxn: false, - command: () => ({dbStats: 1, scale: 1}) - } - }, - { - commandName: "delete", - run: { - inAPIVersion1: true, - shardCommandName: "delete", - command: () => ({delete: "collection", deletes: [{q: {_id: 1}, limit: 1}]}) - }, - explain: { - inAPIVersion1: true, - shardCommandName: "explain", - permittedInTxn: false, - command: () => - ({explain: {delete: "collection", deletes: [{q: {_id: 1}, limit: 1}]}}) - } - }, - { - commandName: "distinct", - run: { - inAPIVersion1: false, - shardCommandName: "distinct", - permittedInTxn: false, - command: () => ({distinct: "collection", key: "x"}) - }, - explain: { - inAPIVersion1: false, - shardCommandName: "explain", - permittedInTxn: false, - command: () => ({explain: {distinct: "collection", key: "x"}}) - }, - }, - { - commandName: "drop", - run: { - inAPIVersion1: true, - shardCommandName: "drop", - permittedInTxn: false, - command: () => ({drop: "collection"}) - } - }, - { - commandName: "dropAllRolesFromDatabase", - run: { - inAPIVersion1: false, - configServerCommandName: "dropAllRolesFromDatabase", - permittedInTxn: false, - setUp: () => assert.commandWorked(st.s0.getDB("db").runCommand( - {createRole: "foo", privileges: [], roles: [], writeConcern: {w: 1}})), - command: () => ({dropAllRolesFromDatabase: 1}) - } - }, - { - commandName: "dropAllUsersFromDatabase", - run: { - inAPIVersion1: false, - configServerCommandName: "dropAllUsersFromDatabase", - permittedInTxn: false, - setUp: () => assert.commandWorked(st.s0.getDB("db").runCommand( - {createUser: "foo", pwd: "bar", roles: [], writeConcern: {w: 1}})), - command: () => ({dropAllUsersFromDatabase: 1}) - } - }, - { - commandName: "dropConnections", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "dropDatabase", - run: { - inAPIVersion1: true, - configServerCommandName: "_configsvrDropDatabase", - shardCommandName: "dropDatabase", - permittedInTxn: false, - command: () => ({dropDatabase: 1}) - } - }, - { - commandName: "dropIndexes", - run: { - inAPIVersion1: true, - shardCommandName: "dropIndexes", - permittedInTxn: false, - command: () => ({dropIndexes: "collection", index: "*"}), - } - }, - { - commandName: "dropRole", - run: { - inAPIVersion1: false, - configServerCommandName: "dropRole", - permittedInTxn: false, - setUp: () => assert.commandWorked(st.s0.getDB("db").runCommand( - {createRole: "foo", privileges: [], roles: [], writeConcern: {w: 1}})), - command: () => ({dropRole: "foo"}) - } - }, - { - commandName: "dropUser", - run: { - inAPIVersion1: false, - configServerCommandName: "dropUser", - permittedInTxn: false, - setUp: () => assert.commandWorked(st.s0.getDB("db").runCommand( - {createUser: "foo", pwd: "bar", roles: [], writeConcern: {w: 1}})), - command: () => ({dropUser: "foo"}) - } - }, - {commandName: "echo", skip: "executes locally on mongos (not sent to any remote node)"}, - { - commandName: "enableSharding", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "endSessions", - skip: "executes locally on mongos (not sent to any remote node)" - }, - {commandName: "explain", skip: "tested by other means"}, - {commandName: "features", skip: "executes locally on mongos (not sent to any remote node)"}, - { - commandName: "filemd5", - run: { - inAPIVersion1: false, - shardCommandName: "filemd5", - permittedInTxn: false, - command: () => ({filemd5: ObjectId(), root: "collection"}) - } - }, - { - commandName: "find", - run: { - inAPIVersion1: true, - shardCommandName: "find", - command: () => ({find: "collection", filter: {x: 1}}) - }, - explain: { - inAPIVersion1: true, - shardCommandName: "explain", - permittedInTxn: false, - command: () => ({explain: {find: "collection", filter: {x: 1}}}) - } - }, - { - commandName: "findAndModify", - run: { - inAPIVersion1: true, - shardCommandName: "findAndModify", - command: () => ({findAndModify: "collection", query: {_id: 0}, remove: true}) - }, - explain: { - inAPIVersion1: true, - shardCommandName: "explain", - permittedInTxn: false, - command: () => - ({explain: {findAndModify: "collection", query: {_id: 0}, remove: true}}) - } - }, - { - commandName: "flushRouterConfig", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "fsync", - run: { - inAPIVersion1: false, - shardCommandName: "fsync", - runsAgainstAdminDb: true, - permittedInTxn: false, - command: () => ({fsync: 1}) - } - }, - { - commandName: "getCmdLineOpts", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "getDefaultRWConcern", - run: { - inAPIVersion1: false, - configServerCommandName: "getDefaultRWConcern", - runsAgainstAdminDb: true, - permittedInTxn: false, - command: () => ({getDefaultRWConcern: 1}) - } - }, - { - commandName: "getDiagnosticData", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "getLastError", - skip: "executes locally on mongos (not sent to any remote node)" - }, - {commandName: "getLog", skip: "executes locally on mongos (not sent to any remote node)"}, - {commandName: "getMore", skip: "prohibits API parameters"}, - { - commandName: "getParameter", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "getShardMap", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "getShardVersion", - skip: "executes locally on mongos (not sent to any remote node)" - }, - {commandName: "getnonce", skip: "executes locally on mongos (not sent to any remote node)"}, - { - commandName: "grantPrivilegesToRole", - run: { - inAPIVersion1: false, - configServerCommandName: "grantPrivilegesToRole", - permittedInTxn: false, - setUp: () => assert.commandWorked(st.s0.getDB("db").runCommand( - {createRole: "foo", privileges: [], roles: [], writeConcern: {w: 1}})), - command: () => ({ - grantPrivilegesToRole: "foo", - privileges: - [{resource: {db: "db", collection: "collection"}, actions: ["find"]}] - }), - cleanUp: () => - assert.commandWorked(st.s0.getDB("db").runCommand({dropRole: "foo"})), - } - }, - { - commandName: "grantRolesToRole", - run: { - inAPIVersion1: false, - configServerCommandName: "grantRolesToRole", - permittedInTxn: false, - setUp: function() { - assert.commandWorked(st.s0.getDB("db").runCommand( - {createRole: "foo", privileges: [], roles: [], writeConcern: {w: 1}})); - assert.commandWorked(st.s0.getDB("db").runCommand( - {createRole: "bar", privileges: [], roles: [], writeConcern: {w: 1}})); - }, - command: () => ({grantRolesToRole: "foo", roles: [{role: "bar", db: "db"}]}), - cleanUp: () => { - assert.commandWorked(st.s0.getDB("db").runCommand({dropRole: "foo"})); - assert.commandWorked(st.s0.getDB("db").runCommand({dropRole: "bar"})); - } - } - }, - { - commandName: "grantRolesToUser", - run: { - inAPIVersion1: false, - configServerCommandName: "grantRolesToUser", - permittedInTxn: false, - setUp: () => { - assert.commandWorked(st.s0.getDB("db").runCommand( - {createUser: "foo", pwd: "bar", roles: [], writeConcern: {w: 1}})); - assert.commandWorked(st.s0.getDB("db").runCommand( - {createRole: "foo", privileges: [], roles: [], writeConcern: {w: 1}})); - }, - command: () => ({grantRolesToUser: "foo", roles: [{role: "foo", db: "db"}]}), - cleanUp: () => { - assert.commandWorked(st.s0.getDB("db").runCommand({dropUser: "foo"})); - assert.commandWorked(st.s0.getDB("db").runCommand({dropRole: "foo"})); - } - } - }, - {commandName: "hello", skip: "executes locally on mongos (not sent to any remote node)"}, - {commandName: "hostInfo", skip: "executes locally on mongos (not sent to any remote node)"}, - { - commandName: "insert", - run: { - inAPIVersion1: true, - shardCommandName: "insert", - command: () => ({insert: "collection", documents: [{_id: 1}]}), - } - }, - { - commandName: "invalidateUserCache", - skip: "executes locally on mongos (not sent to any remote node)" - }, - {commandName: "isdbgrid", skip: "executes locally on mongos (not sent to any remote node)"}, - {commandName: "isMaster", skip: "executes locally on mongos (not sent to any remote node)"}, - { - commandName: "killCursors", - run: - { - inAPIVersion1: true, - shardCommandName: "killCursors", - permittedInTxn: false, - setUp: () => assert.commandWorked(st.s0.getDB("db").runCommand( - {insert: "collection", documents: [{}, {}, {}]})), - command: - () => { - const res = assert.commandWorked( - st.s0.getDB("db").runCommand({find: "collection", batchSize: 1})); - jsTestLog(`res: ${res}`); - const cursorId = res.cursor.id; - return {killCursors: "collection", cursors: [cursorId]}; - } - } - }, - { - commandName: "killAllSessions", - run: { - inAPIVersion1: false, - shardCommandName: "killAllSessionsByPattern", - runsAgainstAdminDb: true, - permittedInTxn: false, - command: () => ({killAllSessions: []}) - } - }, - { - commandName: "killAllSessionsByPattern", - run: { - inAPIVersion1: false, - shardCommandName: "killAllSessionsByPattern", - runsAgainstAdminDb: true, - permittedInTxn: false, - command: () => ({killAllSessionsByPattern: []}) - } - }, - { - commandName: "killOp", - run: { - inAPIVersion1: false, - shardCommandName: "killOp", - permittedInTxn: false, - runsAgainstAdminDb: true, - setUp: (context) => { - function threadRoutine({connStr}) { - const client = new Mongo(connStr); - jsTestLog(`Calling find on "${connStr}" from thread`); - const res = client.getDB("db").runCommand({ - find: "collection", - filter: {$where: "sleep(99999999); return true;"}, - comment: "foo" - }); - jsTestLog(`Called find command: ${tojson(res)}`); - } - - context.thread = new Thread(threadRoutine, {connStr: st.s0.host}); - context.thread.start(); - const adminDb = st.s0.getDB("admin"); - - assert.soon(() => { - const inprog = adminDb.currentOp({"command.comment": "foo"}).inprog; - if (inprog.length === 1) { - context.findOpId = inprog[0].opid; - return true; - } - }); - }, - command: (context) => ({killOp: 1, op: context.findOpId}), - cleanUp: (context) => { - context.thread.join(); - } - } - }, - { - commandName: "killSessions", - run: { - inAPIVersion1: false, - shardCommandName: "killAllSessionsByPattern", - runsAgainstAdminDb: true, - permittedInTxn: false, - setUp: (context) => { - const session = st.s0.startSession(); - context.lsid = session.getSessionId(); - }, - command: (context) => ({killSessions: [context.lsid]}) - } - }, - { - commandName: "listCollections", - run: { - inAPIVersion1: true, - shardCommandName: "listCollections", - permittedInTxn: false, - command: () => ({listCollections: 1}) - } - }, - { - commandName: "listCommands", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "listDatabases", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "listIndexes", - run: { - inAPIVersion1: true, - shardCommandName: "listIndexes", - permittedInTxn: false, - command: () => ({listIndexes: "collection"}), - } - }, - { - commandName: "listShards", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "logApplicationMessage", - skip: "executes locally on mongos (not sent to any remote node)", - conditional: true - }, - { - commandName: "logMessage", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "logRotate", - skip: "executes locally on mongos (not sent to any remote node)" - }, - {commandName: "logout", skip: "executes locally on mongos (not sent to any remote node)"}, - { - commandName: "mapReduce", - run: { - inAPIVersion1: false, - permittedInTxn: false, - shardCommandName: "aggregate", - command: () => ({ - mapReduce: "collection", - map: function mapFunc() { - emit(this.x, 1); - }, - reduce: function reduceFunc(key, values) { - return Array.sum(values); - }, - out: "inline" - }), - }, - explain: { - inAPIVersion1: false, - shardCommandName: "explain", - permittedInTxn: false, - command: () => ({ - explain: { - mapReduce: "collection", - map: function mapFunc() { - emit(this.x, 1); - }, - reduce: function reduceFunc(key, values) { - return Array.sum(values); - }, - out: "inline" - } - }), - } - }, - { - commandName: "mergeChunks", - run: { - inAPIVersion1: false, - shardCommandName: "mergeChunks", - configServerCommandName: "_configsvrCommitChunkMerge", - runsAgainstAdminDb: true, - permittedInTxn: false, - requiresShardedCollection: true, - setUp: () => { - // Collection is already split into chunks [MinKey, 10], (10, MaxKey]. - assert.commandWorked( - st.s.adminCommand({split: "db.collection", middle: {_id: -5}})); - // Now the chunks are: [MinKey, -5], (-5, 10], (10, MaxKey]. - }, - command: () => ({mergeChunks: "db.collection", bounds: [{_id: MinKey}, {_id: 10}]}) - } - }, - { - commandName: "moveChunk", - run: { - inAPIVersion1: false, - shardCommandName: "moveChunk", - configServerCommandName: "_configsvrMoveChunk", - runsAgainstAdminDb: true, - permittedInTxn: false, - requiresShardedCollection: true, - command: () => ({ - moveChunk: "db.collection", - find: {_id: 1}, - to: st.shard1.shardName, - // Don't interfere with the next test case. - _waitForDelete: true - }) - } - }, - { - commandName: "movePrimary", - run: { - inAPIVersion1: false, - configServerCommandName: "_configsvrMovePrimary", - shardCommandName: "_shardsvrMovePrimary", - runsAgainstAdminDb: true, - permittedInTxn: false, - command: () => ({movePrimary: "db", to: st.shard1.shardName}) - } - }, - { - commandName: "multicast", - skip: "executes locally on mongos (not sent to any remote node)" - }, - {commandName: "netstat", skip: "executes locally on mongos (not sent to any remote node)"}, - {commandName: "ping", skip: "executes locally on mongos (not sent to any remote node)"}, - { - commandName: "planCacheClear", - run: { - inAPIVersion1: false, - shardCommandName: "planCacheClear", - permittedInTxn: false, - command: () => ({planCacheClear: "collection"}) - } - }, - { - commandName: "planCacheClearFilters", - run: { - inAPIVersion1: false, - shardCommandName: "planCacheClearFilters", - permittedInTxn: false, - command: () => ({planCacheClearFilters: "collection"}) - } - }, - { - commandName: "planCacheListFilters", - run: { - inAPIVersion1: false, - shardCommandName: "planCacheListFilters", - permittedInTxn: false, - setUp: () => assert.commandWorked(st.s0.getDB("db").runCommand( - {planCacheSetFilter: "collection", query: {_id: 1}, indexes: [{_id: 1}]})), - command: () => ({planCacheListFilters: "collection"}) - } - }, - { - commandName: "planCacheSetFilter", - run: { - inAPIVersion1: false, - shardCommandName: "planCacheSetFilter", - permittedInTxn: false, - command: () => - ({planCacheSetFilter: "collection", query: {_id: 1}, indexes: [{_id: 1}]}), - } - }, - {commandName: "profile", skip: "not supported in mongos"}, - {commandName: "reapLogicalSessionCacheNow", skip: "is a no-op on mongos"}, - { - commandName: "refineCollectionShardKey", - run: { - inAPIVersion1: false, - configServerCommandName: "_configsvrRefineCollectionShardKey", - runsAgainstAdminDb: true, - permittedInTxn: false, - requiresShardedCollection: true, - setUp: () => assert.commandWorked(st.s0.getDB("db").runCommand({ - createIndexes: "collection", - indexes: [{key: {_id: 1, x: 1}, name: "_id-1-x-1"}] - })), - command: () => ({refineCollectionShardKey: "db.collection", key: {_id: 1, x: 1}}) - } - }, - { - commandName: "refreshLogicalSessionCacheNow", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "refreshSessions", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "removeShard", - run: { - inAPIVersion1: false, - runsAgainstAdminDb: true, - configServerCommandName: "_configsvrRemoveShard", - permittedInTxn: false, - command: () => ({removeShard: st.shard0.shardName}), - cleanUp: () => { - // Wait for the shard to be removed completely before re-adding it. - awaitRemoveShard(st.shard0.shardName); - assert.commandWorked(st.s0.getDB("admin").runCommand( - {addShard: st.rs0.getURL(), name: st.shard0.shardName})); - } - } - }, - { - commandName: "removeShardFromZone", - run: { - inAPIVersion1: false, - runsAgainstAdminDb: true, - configServerCommandName: "_configsvrRemoveShardFromZone", - permittedInTxn: false, - setup: () => - assert.commandWorked({addShardToZone: st.shard0.shardName, zone: "foo"}), - command: () => ({removeShardFromZone: st.shard0.shardName, zone: "foo"}) - } - }, - { - commandName: "renameCollection", - run: { - inAPIVersion1: false, - shardCommandName: "renameCollection", - permittedOnShardedCollection: false, - permittedInTxn: false, - runsAgainstAdminDb: true, - command: () => ({renameCollection: "db.collection", to: "db.collection_renamed"}) - } - }, - {commandName: "replSetGetStatus", skip: "not supported in mongos"}, - { - commandName: "resetError", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "reshardCollection", - run: { - inAPIVersion1: false, - permittedInTxn: false, - configServerCommandName: "_configsvrReshardCollection", - requiresShardedCollection: true, - runsAgainstAdminDb: true, - command: () => ({reshardCollection: "db.collection", key: {_id: 1}}) - } - }, - { - commandName: "revokePrivilegesFromRole", - run: { - inAPIVersion1: false, - permittedInTxn: false, - configServerCommandName: "revokePrivilegesFromRole", - setUp: () => assert.commandWorked(st.s0.getDB("db").runCommand({ - createRole: "foo", - privileges: - [{resource: {db: "db", collection: "collection"}, actions: ["find"]}], - roles: [], - writeConcern: {w: 1} - })), - command: () => ({ - revokePrivilegesFromRole: "foo", - privileges: - [{resource: {db: "db", collection: "collection"}, actions: ["find"]}] - }), - cleanUp: () => { - assert.commandWorked(st.s0.getDB("db").runCommand({dropRole: "foo"})); - } - } - }, - { - commandName: "revokeRolesFromRole", - run: { - inAPIVersion1: false, - permittedInTxn: false, - configServerCommandName: "revokeRolesFromRole", - setUp: () => { - assert.commandWorked(st.s0.getDB("db").runCommand( - {createRole: "foo", privileges: [], roles: [], writeConcern: {w: 1}})); - assert.commandWorked(st.s0.getDB("db").runCommand( - {createRole: "bar", privileges: [], roles: [], writeConcern: {w: 1}})); - assert.commandWorked(st.s0.getDB("db").runCommand( - {grantRolesToRole: "foo", roles: [{role: "bar", db: "db"}]})); - }, - command: () => ({revokeRolesFromRole: "foo", roles: [{role: "bar", db: "db"}]}), - cleanUp: () => { - assert.commandWorked(st.s0.getDB("db").runCommand({dropRole: "foo"})); - assert.commandWorked(st.s0.getDB("db").runCommand({dropRole: "bar"})); - } - } - }, - { - commandName: "revokeRolesFromUser", - run: { - inAPIVersion1: false, - configServerCommandName: "revokeRolesFromUser", - permittedInTxn: false, - setUp: () => { - assert.commandWorked(st.s0.getDB("db").runCommand( - {createUser: "foo", pwd: "bar", roles: [], writeConcern: {w: 1}})); - assert.commandWorked(st.s0.getDB("db").runCommand( - {createRole: "foo", privileges: [], roles: [], writeConcern: {w: 1}})); - assert.commandWorked(st.s0.getDB("db").runCommand( - {grantRolesToUser: "foo", roles: [{role: "foo", db: "db"}]})); - }, - command: () => ({revokeRolesFromUser: "foo", roles: [{role: "foo", db: "db"}]}), - cleanUp: () => { - assert.commandWorked(st.s0.getDB("db").runCommand({dropUser: "foo"})); - assert.commandWorked(st.s0.getDB("db").runCommand({dropRole: "foo"})); - } - } - }, - { - commandName: "rolesInfo", - run: { - inAPIVersion1: false, - configServerCommandName: "rolesInfo", - permittedInTxn: false, - command: () => ({rolesInfo: 1}) - } - }, - { - commandName: "rotateCertificates", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "saslContinue", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "saslStart", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "serverStatus", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "setDefaultRWConcern", - run: { - inAPIVersion1: false, - configServerCommandName: "setDefaultRWConcern", - runsAgainstAdminDb: true, - permittedInTxn: false, - command: () => ({setDefaultRWConcern: 1, defaultWriteConcern: {w: 1}}) - } - }, - { - commandName: "setIndexCommitQuorum", - run: { - inAPIVersion1: false, - shardCommandName: "setIndexCommitQuorum", - permittedInTxn: false, - command: () => ({ - setIndexCommitQuorum: "collection", - indexNames: ["index"], - commitQuorum: "majority" - }), - } - }, - { - commandName: "setFeatureCompatibilityVersion", - run: { - inAPIVersion1: false, - configServerCommandName: "setFeatureCompatibilityVersion", - permittedInTxn: false, - runsAgainstAdminDb: true, - command: () => ({setFeatureCompatibilityVersion: latestFCV}) - } - }, - { - commandName: "setFreeMonitoring", - skip: "explicitly fails for mongos, primary mongod only", - conditional: true - }, - { - commandName: "setParameter", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "shardCollection", - run: { - inAPIVersion1: false, - configServerCommandName: "_configsvrShardCollection", - shardCommandName: "_shardsvrShardCollection", - runsAgainstAdminDb: true, - permittedInTxn: false, - permittedOnShardedCollection: false, - setUp: () => { - assert.commandWorked(st.s.adminCommand({enableSharding: "db"})); - st.ensurePrimaryShard("db", st.shard0.shardName); - }, - command: () => ({shardCollection: "db.collection", key: {_id: 1}}) - } - }, - { - commandName: "shardConnPoolStats", - skip: "executes locally on mongos (not sent to any remote node)" - }, - {commandName: "shutdown", skip: "executes locally on mongos (not sent to any remote node)"}, - { - commandName: "split", - run: { - inAPIVersion1: false, - configServerCommandName: "_configsvrCommitChunkSplit", - shardCommandName: "splitChunk", - runsAgainstAdminDb: true, - permittedInTxn: false, - requiresShardedCollection: true, - command: () => ({split: "db.collection", middle: {_id: 5}}) - } - }, - { - commandName: "splitVector", - run: { - inAPIVersion1: false, - shardCommandName: "splitVector", - permittedInTxn: false, - permittedOnShardedCollection: false, - command: () => ({ - splitVector: "db.collection", - keyPattern: {_id: 1}, - min: {_id: 0}, - max: {_id: MaxKey}, - maxChunkSizeBytes: 1024 - }) - } - }, - { - commandName: "startRecordingTraffic", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "startSession", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "stopRecordingTraffic", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "testDeprecation", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "testDeprecationInVersion2", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "testRemoval", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "testVersion2", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "testVersions1And2", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "update", - run: { - inAPIVersion1: true, - shardCommandName: "update", - command: () => ({ - update: "collection", - updates: [{q: {_id: 2}, u: {_id: 2}, upsert: true, multi: false}] - }), - }, - explain: { - inAPIVersion1: true, - shardCommandName: "explain", - permittedInTxn: false, - command: () => ({ - explain: { - update: "collection", - updates: [{q: {_id: 2}, u: {_id: 2}, upsert: true, multi: false}] - } - }), - } - }, - { - commandName: "updateRole", - run: { - inAPIVersion1: false, - configServerCommandName: "updateRole", - permittedInTxn: false, - setUp: () => assert.commandWorked(st.s0.getDB("db").runCommand( - {createRole: "foo", privileges: [], roles: [], writeConcern: {w: 1}})), - command: () => ({updateRole: "foo", authenticationRestrictions: []}), - cleanUp: () => assert.commandWorked( - st.s0.getDB("db").runCommand({dropAllRolesFromDatabase: 1})) - } - }, - { - commandName: "updateUser", - run: { - inAPIVersion1: false, - configServerCommandName: "updateUser", - permittedInTxn: false, - setUp: () => assert.commandWorked(st.s0.getDB("db").runCommand( - {createUser: "foo", pwd: "bar", roles: [], writeConcern: {w: 1}})), - command: () => ({updateUser: "foo", authenticationRestrictions: []}), - cleanUp: () => assert.commandWorked( - st.s0.getDB("db").runCommand({dropAllUsersFromDatabase: 1})) - } - }, - { - commandName: "updateZoneKeyRange", - run: { - inAPIVersion1: false, - configServerCommandName: "_configsvrUpdateZoneKeyRange", - permittedInTxn: false, - runsAgainstAdminDb: true, - setUp: () => assert.commandWorked(st.s0.getDB("admin").runCommand( - {addShardToZone: st.shard0.shardName, zone: "foo"})), - command: () => ({ - updateZoneKeyRange: "db.collection", - min: {_id: 1}, - max: {_id: 5}, - zone: "foo" - }), - cleanUp: () => { - // Remove zone key range. - assert.commandWorked(st.s0.getDB("admin").runCommand({ - updateZoneKeyRange: "db.collection", - min: {_id: 1}, - max: {_id: 5}, - zone: null - })); - assert.commandWorked(st.s0.getDB("admin").runCommand( - {removeShardFromZone: st.shard0.shardName, zone: "foo"})); - } - } - }, - { - commandName: "usersInfo", - run: { - inAPIVersion1: false, - configServerCommandName: "usersInfo", - permittedInTxn: false, - command: () => ({usersInfo: 1}) - } - }, - { - commandName: "validate", - run: { - inAPIVersion1: false, - shardCommandName: "validate", - permittedInTxn: false, - command: () => ({validate: "collection"}), - } - }, - { - commandName: "waitForFailPoint", - skip: "executes locally on mongos (not sent to any remote node)" - }, - { - commandName: "whatsmyuri", - skip: "executes locally on mongos (not sent to any remote node)" - }, - ]; - - commandsRemovedFromMongosSinceLastLTS.forEach(function(cmd) { - testCases[cmd] = { - skip: "must define test coverage for latest version backwards compatibility" - }; - }); - - const st = new ShardingTest({mongos: 1, shards: 2, rs: {nodes: 1}}); - const listCommandsRes = st.s0.adminCommand({listCommands: 1}); - assert.commandWorked(listCommandsRes); - - (() => { - // Validate test cases for all commands. Ensure there is at least one test case for every - // mongos command, and that the test cases are well formed. - for (const command of Object.keys(listCommandsRes.commands)) { - const matchingCases = testCases.filter(elem => elem.commandName === command); - assert(matchingCases !== [], - "coverage failure: must define a test case for " + command); - for (const testCase of matchingCases) { - validateTestCase(testCase); - testCase.validated = true; - } - } - - // After iterating through all the existing commands, ensure there were no additional test - // cases that did not correspond to any mongos command. - for (const testCase of testCases) { - // We have defined real test cases for commands added since the last LTS version so that - // the test cases are exercised in the regular suites, but because these test cases - // can't run in the last stable suite, we skip processing them here to avoid failing the - // below assertion. We have defined "skip" test cases for commands removed since the - // last LTS version so the test case is defined in last stable suites (in which these - // commands still exist on the mongos), but these test cases won't be run in regular - // suites, so we skip processing them below as well. - if (commandsAddedToMongosSinceLastLTS.includes(testCase.commandName) || - commandsRemovedFromMongosSinceLastLTS.includes(testCase.commandName)) - continue; - assert(testCase.validated || testCase.conditional, - "you defined a test case for a command '" + testCase.commandName + - "' that does not exist on mongos: " + tojson(testCase)); - } - })(); - - function checkPrimaryLog(conn, commandName, apiVersion, apiStrict, apiDeprecationErrors) { - const logs = checkLog.getGlobalLog(conn); - let lastCommandInvocation; - - for (let logMsg of logs) { - const obj = JSON.parse(logMsg); - // Search for "About to run the command" logs. - if (obj.id !== 21965) - continue; - - const args = obj.attr.commandArgs; - if (commandName !== Object.keys(args)[0]) - continue; - - lastCommandInvocation = args; - if (args.apiVersion !== apiVersion || args.apiStrict !== apiStrict || - args.apiDeprecationErrors !== apiDeprecationErrors) - continue; - - // Found a match. - return; - } - - if (lastCommandInvocation === undefined) { - doassert(`Primary didn't log ${commandName}`); - return; - } - - doassert(`Primary didn't log ${commandName} with apiVersion ${apiVersion},` + - ` apiStrict ${apiStrict},` + - ` apiDeprecationErrors ${apiDeprecationErrors}.` + - ` Last invocation of ${commandName} was` + - ` ${tojson(lastCommandInvocation)}`); - } - - function runTests({inTransaction, shardedCollection}) { - // For each combination of config parameters and test case, create a test instance. Do this - // before executing the test instances so we can count the number of instances and log - // progress. - let testInstances = []; - - for (const [apiVersion, apiStrict, apiDeprecationErrors] of [ - [undefined, undefined, undefined], - ["1", undefined, undefined], - ["1", undefined, false], - ["1", undefined, true], - ["1", false, undefined], - ["1", false, false], - ["1", false, true], - ["1", true, undefined], - ["1", true, false], - ["1", true, true], - ]) { - for (const testCase of testCases) { - if (testCase.skip) - continue; - - for (let runOrExplain of [testCase.run, testCase.explain]) { - if (runOrExplain === undefined) - continue; - - if (inTransaction && !runOrExplain.permittedInTxn) - continue; - - if (shardedCollection && !runOrExplain.permittedOnShardedCollection) - continue; - - if (!shardedCollection && runOrExplain.requiresShardedCollection) - continue; - - if (apiStrict && !runOrExplain.inAPIVersion1) - continue; - - testInstances.push({ - apiVersion: apiVersion, - apiStrict: apiStrict, - apiDeprecationErrors: apiDeprecationErrors, - commandName: testCase.commandName, - runOrExplain: runOrExplain - }); - } - } - } - - for (let i = 0; i < testInstances.length; ++i) { - const {apiVersion, apiStrict, apiDeprecationErrors, commandName, runOrExplain} = - testInstances[i]; - - if (shardedCollection) { - jsTestLog("Sharded setup"); - assert.commandWorked(st.s.getDB("db")["collection"].insert( - {_id: 0}, {writeConcern: {w: "majority"}})); - assert.commandWorked(st.s.getDB("db")["collection"].insert( - {_id: 20}, {writeConcern: {w: "majority"}})); - - assert.commandWorked(st.s.adminCommand({enableSharding: "db"})); - st.ensurePrimaryShard("db", st.shard0.shardName); - assert.commandWorked( - st.s.adminCommand({shardCollection: "db.collection", key: {_id: 1}})); - - // The chunk with _id 1 is on shard 0. - assert.commandWorked( - st.s.adminCommand({split: "db.collection", middle: {_id: 10}})); - assert.commandWorked(st.s.adminCommand({ - moveChunk: "db.collection", - find: {_id: 20}, - to: st.shard1.shardName, - _waitForDelete: true - })); - } else { - jsTestLog("Unsharded setup"); - assert.commandWorked(st.s.getDB("db")["collection"].insert( - {_id: 0}, {writeConcern: {w: "majority"}})); - st.ensurePrimaryShard("db", st.shard0.shardName); - } - - const configPrimary = st.configRS.getPrimary(); - const shardZeroPrimary = st.rs0.getPrimary(); - const context = {}; - - if (runOrExplain.setUp) { - jsTestLog(`setUp function for ${commandName}`); - runOrExplain.setUp(context); - jsTestLog(`setUp function for ${commandName} completed`); - } - - // Make a copy of the test's command body, and set its API parameters. - const commandDbName = runOrExplain.runsAgainstAdminDb ? "admin" : "db"; - const commandBody = runOrExplain.command(context); - const commandWithAPIParams = Object.assign({}, commandBody); - if (apiVersion !== undefined) { - commandWithAPIParams.apiVersion = apiVersion; - } - - if (apiStrict !== undefined) { - commandWithAPIParams.apiStrict = apiStrict; - } - - if (apiDeprecationErrors !== undefined) { - commandWithAPIParams.apiDeprecationErrors = apiDeprecationErrors; - } - - assert.commandWorked(configPrimary.adminCommand({clearLog: "global"})); - assert.commandWorked(shardZeroPrimary.adminCommand({clearLog: "global"})); - const message = - `[${i + 1} of ${testInstances.length}]: command ${tojson(commandWithAPIParams)}` + - ` ${shardedCollection ? "sharded" : "unsharded"},` + - ` ${inTransaction ? "in" : "outside"} transaction` + - ` on "${commandDbName}" database`; - - flushRoutersAndRefreshShardMetadata(st, {ns: "db.collection"}); - - jsTestLog(`Running ${message}`); - setLogVerbosity([configPrimary, shardZeroPrimary], {"command": {"verbosity": 2}}); - - if (inTransaction) { - const session = st.s0.startSession(); - const sessionDb = session.getDatabase(commandDbName); - session.startTransaction(); - assert.commandWorked(sessionDb.runCommand(commandWithAPIParams)); - assert.commandWorked(session.commitTransaction_forTesting()); - } else { - const db = st.s0.getDB(commandDbName); - assert.commandWorked(db.runCommand(commandWithAPIParams)); - } - - setLogVerbosity([configPrimary, shardZeroPrimary], {"command": {"verbosity": 0}}); - - const configServerCommandName = runOrExplain.configServerCommandName; - const shardCommandName = runOrExplain.shardCommandName; - - if (configServerCommandName) { - jsTestLog(`Check for ${configServerCommandName} in config server's log`); - checkPrimaryLog(configPrimary, - configServerCommandName, - apiVersion, - apiStrict, - apiDeprecationErrors); - } - - if (shardCommandName) { - jsTestLog(`Check for ${shardCommandName} in shard server's log`); - checkPrimaryLog(shardZeroPrimary, - shardCommandName, - apiVersion, - apiStrict, - apiDeprecationErrors); - } - - st.s0.getDB("db").runCommand({dropDatabase: 1}); - if (runOrExplain.cleanUp) { - jsTestLog(`cleanUp function for ${commandName}`); - runOrExplain.cleanUp(context); - jsTestLog(`cleanUp function for ${commandName} completed`); - } - } - - st.stop(); - } - - return {runTests: runTests}; -})(); diff --git a/jstests/sharding/mongos_forwards_api_parameters_to_shards.js b/jstests/sharding/mongos_forwards_api_parameters_to_shards.js new file mode 100644 index 00000000000..e611f716992 --- /dev/null +++ b/jstests/sharding/mongos_forwards_api_parameters_to_shards.js @@ -0,0 +1,213 @@ +/** + * When a client calls a mongos command with API parameters, mongos must forward them to shards. + * + * @tags: [multiversion_incompatible] + */ + +(function() { +'use strict'; + +load('jstests/sharding/libs/sharded_transactions_helpers.js'); + +let st = new ShardingTest({ + mongos: 1, + shards: 2, + rs: {nodes: 1, setParameter: {logComponentVerbosity: tojson({command: {verbosity: 2}})}} +}); + +class APIParameterTest { + constructor( + command, + {dbName = "db", inAPIVersion1 = true, permittedInTxn = true, shardCommandName} = {}) { + this.command = command; + this.dbName = dbName; + this.inAPIVersion1 = inAPIVersion1; + this.permittedInTxn = permittedInTxn; + if (shardCommandName === undefined) { + this.commandName = Object.keys(command)[0]; + } else { + // mongos executes a different command on the shards, e.g. mapReduce becomes aggregate. + this.commandName = shardCommandName; + } + } +} + +const tests = [ + // Write commands. Note, these rely on _id 1 residing on shard 0. + new APIParameterTest({insert: "collection", documents: [{_id: 1}]}), + new APIParameterTest({update: "collection", updates: [{q: {_id: 1}, u: {$set: {x: 1}}}]}), + new APIParameterTest({delete: "collection", deletes: [{q: {_id: 1}, limit: 1}]}), + + // Read commands. + new APIParameterTest({aggregate: "collection", pipeline: [], cursor: {}}), + new APIParameterTest({aggregate: "collection", pipeline: [], cursor: {}, explain: true}, + {shardCommandName: "explain", permittedInTxn: false}), + new APIParameterTest({find: "collection"}), + new APIParameterTest({count: "collection"}, {permittedInTxn: false}), + new APIParameterTest({count: "collection", query: {_id: {$lt: 0}}}, + {inAPIVersion1: false, permittedInTxn: false}), + new APIParameterTest({distinct: "collection", key: "_id"}, + {inAPIVersion1: false, permittedInTxn: false}), + new APIParameterTest( + { + mapReduce: "collection", + map: function() { + emit(1, 1); + }, + reduce: function(key, values) { + return {count: values.length}; + }, + out: {inline: 1} + }, + {inAPIVersion1: false, permittedInTxn: false, shardCommandName: "aggregate"}), + + // FindAndModify. + new APIParameterTest({findAndModify: "collection", query: {_id: 1}, remove: true}), + + // DDL. Order matters: we must create, modify, then drop an index on collection2. + new APIParameterTest({createIndexes: "collection2", indexes: [{key: {x: 1}, name: "x_1"}]}), + new APIParameterTest({collMod: "collection2", index: {keyPattern: {x: 1}, hidden: true}}, + {permittedInTxn: false}), + new APIParameterTest({dropIndexes: "collection2", index: "x_1"}, {permittedInTxn: false}), + // We can create indexes on a non-existent collection in a sharded transaction. + new APIParameterTest({create: "newCollection"}), + new APIParameterTest({renameCollection: "db.newCollection", to: "db.newerCollection"}, + {inAPIVersion1: false, permittedInTxn: false, dbName: "admin"}), + new APIParameterTest({drop: "collection"}, {permittedInTxn: false}), + new APIParameterTest({dropDatabase: 1}, {permittedInTxn: false}), +]; + +function checkPrimaryLog(conn, commandName, apiVersion, apiStrict, apiDeprecationErrors, message) { + const logs = checkLog.getGlobalLog(conn); + let lastCommandInvocation; + + for (let logMsg of logs) { + const obj = JSON.parse(logMsg); + // Search for "About to run the command" logs. + if (obj.id !== 21965) { + continue; + } + + const args = obj.attr.commandArgs; + if (commandName !== Object.keys(args)[0]) { + continue; + } + + lastCommandInvocation = args; + if (args.apiVersion !== apiVersion || args.apiStrict !== apiStrict || + args.apiDeprecationErrors !== apiDeprecationErrors) { + continue; + } + + // Found a match. + return; + } + + if (lastCommandInvocation === undefined) { + doassert(`Primary didn't log ${commandName}`); + return; + } + + doassert(`Primary didn't log ${message}, last invocation of ${commandName} was` + + ` ${tojson(lastCommandInvocation)}`); +} + +for (const sharded of [false, true]) { + for (const [apiVersion, apiStrict, apiDeprecationErrors] of [[undefined, undefined, undefined], + ["1", undefined, undefined], + ["1", undefined, false], + ["1", undefined, true], + ["1", false, undefined], + ["1", false, false], + ["1", false, true], + ["1", true, undefined], + ["1", true, false], + ["1", true, true], + ]) { + for (let inTransaction of [false, true]) { + if (sharded) { + jsTestLog("Sharded setup"); + assert.commandWorked(st.s.getDB("db")["collection"].insert( + {_id: 0}, {writeConcern: {w: "majority"}})); + assert.commandWorked(st.s.getDB("db")["collection"].insert( + {_id: 20}, {writeConcern: {w: "majority"}})); + + assert.commandWorked(st.s.adminCommand({enableSharding: "db"})); + st.ensurePrimaryShard("db", st.shard0.shardName); + assert.commandWorked( + st.s.adminCommand({shardCollection: "db.collection", key: {_id: 1}})); + + // The chunk with _id 1 is on shard 0. + assert.commandWorked( + st.s.adminCommand({split: "db.collection", middle: {_id: 10}})); + assert.commandWorked(st.s.adminCommand( + {moveChunk: "db.collection", find: {_id: 20}, to: st.shard1.shardName})); + } else { + jsTestLog("Unsharded setup"); + assert.commandWorked(st.s.getDB("db")["collection"].insert( + {_id: 0}, {writeConcern: {w: "majority"}})); + st.ensurePrimaryShard("db", st.shard0.shardName); + } + + // Shard 0's primary. + const primary = st.rs0.getPrimary(); + + for (const test of tests) { + if (inTransaction && !test.permittedInTxn) { + continue; + } + + if (apiStrict && !test.inAPIVersion1) { + continue; + } + + // Make a copy of the test's command body, and set its API parameters. + const commandWithAPIParams = Object.assign({}, test.command); + if (apiVersion !== undefined) { + commandWithAPIParams.apiVersion = apiVersion; + } + + if (apiStrict !== undefined) { + commandWithAPIParams.apiStrict = apiStrict; + } + + if (apiDeprecationErrors !== undefined) { + commandWithAPIParams.apiDeprecationErrors = apiDeprecationErrors; + } + + assert.commandWorked(primary.adminCommand({clearLog: "global"})); + const message = `command ${tojson(commandWithAPIParams)}` + + ` ${sharded ? "sharded" : "unsharded"},` + + ` ${inTransaction ? "in" : "outside"} transaction`; + + flushRoutersAndRefreshShardMetadata(st, {ns: "db.collection"}); + + jsTestLog(`Running ${message}`); + + if (inTransaction) { + const session = st.s0.startSession(); + const sessionDb = session.getDatabase(test.dbName); + session.startTransaction(); + assert.commandWorked(sessionDb.runCommand(commandWithAPIParams)); + assert.commandWorked(session.commitTransaction_forTesting()); + } else { + const db = st.s0.getDB(test.dbName); + assert.commandWorked(db.runCommand(commandWithAPIParams)); + } + + checkPrimaryLog(primary, + test.commandName, + apiVersion, + apiStrict, + apiDeprecationErrors, + message); + } + + jsTestLog("JS test cleanup: Drop database 'db'"); + st.s0.getDB("db").runCommand({dropDatabase: 1}); + } + } +} + +st.stop(); +})(); diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript index bc8de0aa6c9..e813b2067c5 100644 --- a/src/mongo/db/SConscript +++ b/src/mongo/db/SConscript @@ -1524,7 +1524,6 @@ env.Library( '$BUILD_DIR/mongo/db/auth/auth', '$BUILD_DIR/mongo/db/auth/authprivilege', '$BUILD_DIR/mongo/idl/idl_parser', - 'api_parameters', ], ) diff --git a/src/mongo/db/api_parameters.cpp b/src/mongo/db/api_parameters.cpp index 51e424637db..05ffe9c49cb 100644 --- a/src/mongo/db/api_parameters.cpp +++ b/src/mongo/db/api_parameters.cpp @@ -76,18 +76,4 @@ void APIParameters::appendInfo(BSONObjBuilder* builder) const { } } -std::size_t APIParameters::Hash::operator()(const APIParameters& params) const { - size_t seed = 0; - if (params.getAPIVersion()) { - boost::hash_combine(seed, *params.getAPIVersion()); - } - if (params.getAPIStrict()) { - boost::hash_combine(seed, *params.getAPIStrict()); - } - if (params.getAPIDeprecationErrors()) { - boost::hash_combine(seed, *params.getAPIDeprecationErrors()); - } - return seed; -} - } // namespace mongo diff --git a/src/mongo/db/api_parameters.h b/src/mongo/db/api_parameters.h index 34c129bca15..efbebfabfcc 100644 --- a/src/mongo/db/api_parameters.h +++ b/src/mongo/db/api_parameters.h @@ -49,11 +49,6 @@ public: static APIParameters fromClient(const APIParametersFromClient& apiParamsFromClient); static APIParameters fromBSON(const BSONObj& cmdObj); - // For use with unordered_map. - struct Hash { - std::size_t operator()(const APIParameters& params) const; - }; - void appendInfo(BSONObjBuilder* builder) const; const boost::optional<std::string>& getAPIVersion() const { @@ -90,14 +85,6 @@ private: boost::optional<bool> _apiDeprecationErrors; }; -inline bool operator==(const APIParameters& lhs, const APIParameters& rhs) { - return lhs.getAPIVersion() == rhs.getAPIVersion() && lhs.getAPIStrict() == rhs.getAPIStrict() && - lhs.getAPIDeprecationErrors() == rhs.getAPIDeprecationErrors(); -} - -inline bool operator!=(const APIParameters& lhs, const APIParameters& rhs) { - return !(lhs == rhs); -} /** * Temporarily remove the user's API parameters from an OperationContext. diff --git a/src/mongo/db/commands/kill_all_sessions_by_pattern_command.cpp b/src/mongo/db/commands/kill_all_sessions_by_pattern_command.cpp index 220c585ae78..c7687db6782 100644 --- a/src/mongo/db/commands/kill_all_sessions_by_pattern_command.cpp +++ b/src/mongo/db/commands/kill_all_sessions_by_pattern_command.cpp @@ -96,10 +96,7 @@ public: // The empty command kills all if (ksc.getKillAllSessionsByPattern().empty()) { - auto item = makeKillAllSessionsByPattern(opCtx); - std::vector<mongo::KillAllSessionsByPattern> patterns; - patterns.push_back({std::move(item.pattern)}); - ksc.setKillAllSessionsByPattern(std::move(patterns)); + ksc.setKillAllSessionsByPattern({makeKillAllSessionsByPattern(opCtx)}); } else { // If a pattern is passed, you may only pass impersonate data if you have the // impersonate privilege. @@ -117,10 +114,8 @@ public: } } - KillAllSessionsByPatternSet patterns; - for (auto& pattern : ksc.getKillAllSessionsByPattern()) { - patterns.insert({std::move(pattern), APIParameters::get(opCtx)}); - } + KillAllSessionsByPatternSet patterns{ksc.getKillAllSessionsByPattern().begin(), + ksc.getKillAllSessionsByPattern().end()}; uassertStatusOK(killSessionsCmdHelper(opCtx, result, patterns)); return true; diff --git a/src/mongo/db/commands/kill_sessions_command.cpp b/src/mongo/db/commands/kill_sessions_command.cpp index 1bb9c2e3a08..41e3596938f 100644 --- a/src/mongo/db/commands/kill_sessions_command.cpp +++ b/src/mongo/db/commands/kill_sessions_command.cpp @@ -63,9 +63,9 @@ KillAllSessionsByPatternSet patternsForLoggedInUser(OperationContext* opCtx) { User* user = authzSession->lookupUser(*iter); invariant(user); - auto item = makeKillAllSessionsByPattern(opCtx); - item.pattern.setUid(user->getDigest()); - patterns.emplace(std::move(item)); + auto pattern = makeKillAllSessionsByPattern(opCtx); + pattern.setUid(user->getDigest()); + patterns.emplace(std::move(pattern)); } } else { patterns.emplace(makeKillAllSessionsByPattern(opCtx)); diff --git a/src/mongo/db/kill_sessions.cpp b/src/mongo/db/kill_sessions.cpp index b167e14c156..41033d23bbb 100644 --- a/src/mongo/db/kill_sessions.cpp +++ b/src/mongo/db/kill_sessions.cpp @@ -31,7 +31,6 @@ #include "mongo/db/kill_sessions.h" -#include "mongo/db/api_parameters.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/client.h" #include "mongo/db/operation_context.h" @@ -97,25 +96,27 @@ std::tuple<std::vector<UserName>, std::vector<RoleName>> getKillAllSessionsByPat return out; } -KillAllSessionsByPatternItem makeKillAllSessionsByPattern(OperationContext* opCtx) { +KillAllSessionsByPattern makeKillAllSessionsByPattern(OperationContext* opCtx) { KillAllSessionsByPattern kasbp; kasbp.setUsers(getKillAllSessionsImpersonateUsers(opCtx)); kasbp.setRoles(getKillAllSessionsImpersonateRoles(opCtx)); - return {kasbp, APIParameters::get(opCtx)}; + + return kasbp; } -KillAllSessionsByPatternItem makeKillAllSessionsByPattern(OperationContext* opCtx, - const KillAllSessionsUser& kasu) { - KillAllSessionsByPatternItem item = makeKillAllSessionsByPattern(opCtx); +KillAllSessionsByPattern makeKillAllSessionsByPattern(OperationContext* opCtx, + const KillAllSessionsUser& kasu) { + KillAllSessionsByPattern kasbp = makeKillAllSessionsByPattern(opCtx); auto authMgr = AuthorizationManager::get(opCtx->getServiceContext()); UserName un(kasu.getUser(), kasu.getDb()); auto user = uassertStatusOK(authMgr->acquireUser(opCtx, un)); - item.pattern.setUid(user->getDigest()); - return item; + kasbp.setUid(user->getDigest()); + + return kasbp; } KillAllSessionsByPatternSet makeSessionFilterForAuthenticatedUsers(OperationContext* opCtx) { @@ -126,18 +127,18 @@ KillAllSessionsByPatternSet makeSessionFilterForAuthenticatedUsers(OperationCont if (auto user = authSession->lookupUser(*it)) { KillAllSessionsByPattern pattern; pattern.setUid(user->getDigest()); - KillAllSessionsByPatternItem item{std::move(pattern), APIParameters::get(opCtx)}; - patterns.emplace(std::move(item)); + patterns.emplace(std::move(pattern)); } } return patterns; } -KillAllSessionsByPatternItem makeKillAllSessionsByPattern(OperationContext* opCtx, - const LogicalSessionId& lsid) { - auto item = makeKillAllSessionsByPattern(opCtx); - item.pattern.setLsid(lsid); - return item; +KillAllSessionsByPattern makeKillAllSessionsByPattern(OperationContext* opCtx, + const LogicalSessionId& lsid) { + KillAllSessionsByPattern kasbp = makeKillAllSessionsByPattern(opCtx); + kasbp.setLsid(lsid); + + return kasbp; } } // namespace mongo diff --git a/src/mongo/db/kill_sessions.h b/src/mongo/db/kill_sessions.h index 31ceeed9375..29909fd49df 100644 --- a/src/mongo/db/kill_sessions.h +++ b/src/mongo/db/kill_sessions.h @@ -31,7 +31,6 @@ #include <tuple> -#include "mongo/db/api_parameters.h" #include "mongo/db/auth/role_name.h" #include "mongo/db/auth/user_name.h" #include "mongo/db/kill_sessions_gen.h" @@ -42,14 +41,8 @@ namespace mongo { class OperationContext; class ServiceContext; -struct KillAllSessionsByPatternItem { - KillAllSessionsByPattern pattern; - APIParameters apiParameters; -}; - -struct KillAllSessionsByPatternItemHash { - std::size_t operator()(const KillAllSessionsByPatternItem& item) const { - auto& pattern = item.pattern; +struct KillAllSessionsByPatternHash { + std::size_t operator()(const KillAllSessionsByPattern& pattern) const { if (pattern.getLsid()) { return lsidHasher(*pattern.getLsid()); } else if (pattern.getUid()) { @@ -67,22 +60,20 @@ struct KillAllSessionsByPatternItemHash { /** * Patterns are specifically equal if they differ only by impersonate data. */ -inline bool operator==(const KillAllSessionsByPatternItem& lhs, - const KillAllSessionsByPatternItem& rhs) { - auto makeEqualityLens = [](const auto& item) { - return std::tie(item.pattern.getLsid(), item.pattern.getUid(), item.apiParameters); +inline bool operator==(const KillAllSessionsByPattern& lhs, const KillAllSessionsByPattern& rhs) { + auto makeEqualityLens = [](const auto& pattern) { + return std::tie(pattern.getLsid(), pattern.getUid()); }; return makeEqualityLens(lhs) == makeEqualityLens(rhs); } -inline bool operator!=(const KillAllSessionsByPatternItem& lhs, - const KillAllSessionsByPatternItem& rhs) { +inline bool operator!=(const KillAllSessionsByPattern& lhs, const KillAllSessionsByPattern& rhs) { return !(lhs == rhs); } using KillAllSessionsByPatternSet = - stdx::unordered_set<KillAllSessionsByPatternItem, KillAllSessionsByPatternItemHash>; + stdx::unordered_set<KillAllSessionsByPattern, KillAllSessionsByPatternHash>; std::tuple<std::vector<UserName>, std::vector<RoleName>> getKillAllSessionsByPatternImpersonateData( const KillAllSessionsByPattern& pattern); @@ -95,13 +86,13 @@ std::tuple<std::vector<UserName>, std::vector<RoleName>> getKillAllSessionsByPat /** * Constructs a kill sessions pattern which kills all sessions */ -KillAllSessionsByPatternItem makeKillAllSessionsByPattern(OperationContext* opCtx); +KillAllSessionsByPattern makeKillAllSessionsByPattern(OperationContext* opCtx); /** * Constructs a kill sessions pattern for a particular user */ -KillAllSessionsByPatternItem makeKillAllSessionsByPattern(OperationContext* opCtx, - const KillAllSessionsUser& user); +KillAllSessionsByPattern makeKillAllSessionsByPattern(OperationContext* opCtx, + const KillAllSessionsUser& user); /** * Constructs a KillAllSessionsByPatternSet, each element of which matches the UID of a user that is @@ -112,7 +103,7 @@ KillAllSessionsByPatternSet makeSessionFilterForAuthenticatedUsers(OperationCont /** * Constructs a kill sessions pattern for a particular logical session */ -KillAllSessionsByPatternItem makeKillAllSessionsByPattern(OperationContext* opCtx, - const LogicalSessionId& lsid); +KillAllSessionsByPattern makeKillAllSessionsByPattern(OperationContext* opCtx, + const LogicalSessionId& lsid); } // namespace mongo diff --git a/src/mongo/db/s/config/sharding_catalog_manager_shard_operations.cpp b/src/mongo/db/s/config/sharding_catalog_manager_shard_operations.cpp index b82c0b908e5..d10ba0288d3 100644 --- a/src/mongo/db/s/config/sharding_catalog_manager_shard_operations.cpp +++ b/src/mongo/db/s/config/sharding_catalog_manager_shard_operations.cpp @@ -43,7 +43,6 @@ #include "mongo/client/read_preference.h" #include "mongo/client/remote_command_targeter.h" #include "mongo/client/replica_set_monitor.h" -#include "mongo/db/api_parameters.h" #include "mongo/db/audit.h" #include "mongo/db/catalog_raii.h" #include "mongo/db/client.h" @@ -146,7 +145,7 @@ StatusWith<Shard::CommandResponse> ShardingCatalogManager::_runCommandForAddShar auto host = std::move(swHost.getValue()); executor::RemoteCommandRequest request( - host, dbName.toString(), cmdObj, rpc::makeEmptyMetadata(), opCtx, Seconds(30)); + host, dbName.toString(), cmdObj, rpc::makeEmptyMetadata(), nullptr, Seconds(30)); executor::RemoteCommandResponse response = Status(ErrorCodes::InternalError, "Internal error running command"); diff --git a/src/mongo/db/session_killer.cpp b/src/mongo/db/session_killer.cpp index 8ac4764398a..20ba36ac3dd 100644 --- a/src/mongo/db/session_killer.cpp +++ b/src/mongo/db/session_killer.cpp @@ -85,19 +85,18 @@ SessionKiller::ReapResult::ReapResult() : result(std::make_shared<boost::optiona SessionKiller::Matcher::Matcher(KillAllSessionsByPatternSet&& patterns) : _patterns(std::move(patterns)) { - for (const auto& item : _patterns) { - auto& pattern = item.pattern; + for (const auto& pattern : _patterns) { if (pattern.getUid()) { _uids.emplace(pattern.getUid().get(), &pattern); } else if (pattern.getLsid()) { _lsids.emplace(pattern.getLsid().get(), &pattern); } else { // If we're killing everything, it's the only pattern we care about. - decltype(_patterns) onlyKillAll{{item}}; + decltype(_patterns) onlyKillAll{{pattern}}; using std::swap; swap(_patterns, onlyKillAll); - _killAll = &(_patterns.begin()->pattern); + _killAll = &(*_patterns.begin()); break; } } @@ -178,38 +177,19 @@ void SessionKiller::_periodicKill(OperationContext* opCtx, stdx::unique_lock<Lat // Drop the lock and run the killer. lk.unlock(); - // Group patterns with equal API parameters into sets. - stdx::unordered_map<APIParameters, KillAllSessionsByPatternSet, APIParameters::Hash> sets; - for (auto& item : nextToReap) { - sets[item.apiParameters].insert(std::move(item)); + Matcher matcher(std::move(nextToReap)); + boost::optional<Result> results; + try { + results.emplace(_killFunc(opCtx, matcher, &_urbg)); + } catch (...) { + results.emplace(exceptionToStatus()); } + lk.lock(); - // Use the API parameters included in each KillAllSessionsByPattern struct. - IgnoreAPIParametersBlock ignoreApiParametersBlock(opCtx); - Result finalResults{std::vector<HostAndPort>{}}; - for (auto& [apiParameters, items] : sets) { - APIParameters::get(opCtx) = apiParameters; - Matcher matcher(std::move(items)); - boost::optional<Result> results; - try { - results.emplace(_killFunc(opCtx, matcher, &_urbg)); - } catch (...) { - results.emplace(exceptionToStatus()); - } - invariant(results); - if (!results->isOK()) { - finalResults = *results; - break; - } - - finalResults.getValue().insert(finalResults.getValue().end(), - std::make_move_iterator(results->getValue().begin()), - std::make_move_iterator(results->getValue().end())); - } + invariant(results); // Expose the results and notify callers - lk.lock(); - *(reapResults.result) = std::move(finalResults); + *(reapResults.result) = std::move(results); _callerCV.notify_all(); }; diff --git a/src/mongo/s/commands/cluster_kill_op.cpp b/src/mongo/s/commands/cluster_kill_op.cpp index 2ce1ecf79ef..1d4927b0f79 100644 --- a/src/mongo/s/commands/cluster_kill_op.cpp +++ b/src/mongo/s/commands/cluster_kill_op.cpp @@ -38,7 +38,6 @@ #include "mongo/bson/bsonobjbuilder.h" #include "mongo/bson/util/bson_extract.h" #include "mongo/client/connpool.h" -#include "mongo/db/api_parameters.h" #include "mongo/db/audit.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" @@ -112,10 +111,8 @@ private: result.append("shardid", opId); ScopedDbConnection conn(shard->getConnString()); - BSONObjBuilder bob(BSON("killOp" << 1 << "op" << opId)); - APIParameters::get(opCtx).appendInfo(&bob); // intentionally ignore return value - that is how legacy killOp worked. - conn->runCommand(OpMsgRequest::fromDBAndBody("admin", bob.obj())); + conn->runCommand(OpMsgRequest::fromDBAndBody("admin", BSON("killOp" << 1 << "op" << opId))); conn.done(); // The original behavior of killOp on mongos is to always return success, regardless of diff --git a/src/mongo/s/commands/kill_sessions_remote.cpp b/src/mongo/s/commands/kill_sessions_remote.cpp index 0102de0d580..d9b5ce26ccf 100644 --- a/src/mongo/s/commands/kill_sessions_remote.cpp +++ b/src/mongo/s/commands/kill_sessions_remote.cpp @@ -119,11 +119,9 @@ SessionKiller::Result killSessionsRemote(OperationContext* opCtx, // Generate the kill command. KillAllSessionsByPatternCmd cmd; - std::vector<KillAllSessionsByPattern> patterns{matcher.getPatterns().size()}; - for (auto& item : matcher.getPatterns()) { - patterns.push_back(std::move(item.pattern)); - } - cmd.setKillAllSessionsByPattern(std::move(patterns)); + cmd.setKillAllSessionsByPattern(std::vector<KillAllSessionsByPattern>{ + matcher.getPatterns().begin(), matcher.getPatterns().end()}); + return parallelExec(opCtx, cmd.toBSON(), urbg); } |