diff options
author | PV99 <pridhvi.vegesna@mongodb.com> | 2020-07-15 23:13:33 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-07-28 23:56:02 +0000 |
commit | 4e0f81726fc11becd9c22d701e80ba2c8d988bb0 (patch) | |
tree | 620edb4e906caa933c4f6cd1d04bce42b290be98 | |
parent | 165dfb50f7693cadb80e988d08222700b1cc6b5c (diff) | |
download | mongo-4e0f81726fc11becd9c22d701e80ba2c8d988bb0.tar.gz |
SERVER-49065 Mark API Version 1 commands
62 files changed, 442 insertions, 8 deletions
diff --git a/jstests/core/version_api_field_parsing.js b/jstests/core/version_api_field_parsing.js index 524c4749338..69505698559 100644 --- a/jstests/core/version_api_field_parsing.js +++ b/jstests/core/version_api_field_parsing.js @@ -7,6 +7,7 @@ (function() { "use strict"; +// Test parsing logic on command included in API V1. // If the client passed apiStrict, they must also pass apiVersion. assert.commandFailedWithCode(db.runCommand({ping: 1, apiStrict: true}), 4886600, @@ -44,4 +45,24 @@ assert.commandWorked( assert.commandWorked( db.runCommand({ping: 1, apiVersion: "1", apiStrict: false, apiDeprecationErrors: false})); assert.commandWorked(db.runCommand({ping: 1, apiVersion: "1"})); + +// Test parsing logic on command not included in API V1. +assert.commandWorked(db.runCommand({listCommands: 1, apiVersion: "1"})); +// If the client passed apiStrict: true, but the command is not in V1, reply with +// APIStrictError. +assert.commandFailedWithCode( + db.runCommand({listCommands: 1, apiVersion: "1", apiStrict: true}), + ErrorCodes.APIStrictError, + "Provided apiStrict: true, but the invoked command's apiVersions() does not include \"1\""); +assert.commandWorked(db.runCommand({listCommands: 1, apiVersion: "1", apiDeprecationErrors: true})); + +// Test parsing logic of command deprecated in API V1. +assert.commandWorked(db.runCommand({testDeprecation: 1, apiVersion: "1"})); +assert.commandWorked(db.runCommand({testDeprecation: 1, apiVersion: "1", apiStrict: true})); +// If the client passed apiDeprecationErrors: true, but the command is +// deprecated in API Version 1, reply with APIDeprecationError. +assert.commandFailedWithCode( + db.runCommand({testDeprecation: 1, apiVersion: "1", apiDeprecationErrors: true}), + ErrorCodes.APIDeprecationError, + "Provided apiDeprecationErrors: true, but the invoked command's deprecatedApiVersions() does not include \"1\""); })();
\ No newline at end of file diff --git a/jstests/core/version_api_v1_command_coverage.js b/jstests/core/version_api_v1_command_coverage.js new file mode 100644 index 00000000000..7364990f48e --- /dev/null +++ b/jstests/core/version_api_v1_command_coverage.js @@ -0,0 +1,81 @@ +/** + * Checks that commands included/omitted in API V1 behave correctly with various combinations of API + * parameters. + * + * @tags: [requires_fcv_46, requires_non_retryable_commands] + */ + +(function() { +"use strict"; + +let counter = 0; +const counter_fun = function() { + return `APIV1-${counter}`; +}; + +const testDB = db.getSiblingDB(jsTestName()); +const testColl = testDB.getCollection("test"); + +function runTest({cmd, apiVersion1, apiStrict, apiDeprecationErrors}) { + // Instantiate "cmd" so we can modify it. + let copy = cmd(); + jsTestLog( + `Test ${tojson(copy)}, which is ${apiVersion1 ? "in" : "not in"} API V1, with apiStrict = ${ + apiStrict} and apiDeprecationErrors = ${apiDeprecationErrors}`); + copy.apiVersion = "1"; + copy.apiStrict = apiStrict; + copy.apiDeprecationErrors = apiDeprecationErrors; + if (!apiVersion1 && apiStrict) { + assert.commandFailedWithCode( + testDB.runCommand(copy), + ErrorCodes.APIStrictError, + "Provided apiStrict: true, but the invoked command's apiVersions() does not include \"1\""); + } else { + assert.commandWorked(testDB.runCommand(copy)); + } +} + +const commands = [ + {cmd: () => ({buildInfo: 1}), apiVersion1: false}, + {cmd: () => ({createUser: counter_fun(), pwd: "pwd", roles: []}), apiVersion1: false}, + {cmd: () => ({dropUser: counter_fun()}), apiVersion1: false}, + {cmd: () => ({getLastError: 1}), apiVersion1: false}, + {cmd: () => ({serverStatus: 1}), apiVersion1: false}, + {cmd: () => ({usersInfo: 1}), apiVersion1: false}, + {cmd: () => ({aggregate: testColl.getName(), pipeline: [], cursor: {}}), apiVersion1: true}, + {cmd: () => ({count: "system.js"}), apiVersion1: true}, + {cmd: () => ({create: counter_fun()}), apiVersion1: true}, + {cmd: () => ({find: counter_fun()}), apiVersion1: true}, + { + cmd: () => ({insert: "APIV1-0", documents: [{_id: counter_fun(), cast: "jonSnow"}]}), + apiVersion1: true + }, + { + cmd: () => ({ + update: "APIV1-0", + updates: [{q: {_id: counter_fun()}, u: {$set: {cast: "aryaStark"}}}] + }), + apiVersion1: true, + }, + { + cmd: () => ({delete: "APIV1-0", deletes: [{q: {_id: counter_fun()}, limit: 1}]}), + apiVersion1: true + }, + {cmd: () => ({drop: counter_fun()}), apiVersion1: true} +]; + +for (let {cmd, apiVersion1} of commands) { + counter = 0; + for (let apiStrict of [false, true]) { + for (let apiDeprecationErrors of [false, true]) { + runTest({ + cmd: cmd, + apiVersion1: apiVersion1, + apiStrict: apiStrict, + apiDeprecationErrors: apiDeprecationErrors + }); + counter += 1; + } + } +} +})();
\ No newline at end of file diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js index 672cdd38f97..1f87251c9fb 100644 --- a/jstests/core/views/views_all_commands.js +++ b/jstests/core/views/views_all_commands.js @@ -546,6 +546,7 @@ let viewsCommandTests = { startRecordingTraffic: {skip: isUnrelated}, startSession: {skip: isAnInternalCommand}, stopRecordingTraffic: {skip: isUnrelated}, + testDeprecation: {skip: isAnInternalCommand}, top: {skip: "tested in views/views_stats.js"}, touch: {skip: wasRemovedInBinaryVersion44}, unsetSharding: {skip: isAnInternalCommand}, diff --git a/jstests/replsets/db_reads_while_recovering_all_commands.js b/jstests/replsets/db_reads_while_recovering_all_commands.js index 1d7c13742df..467b06c1363 100644 --- a/jstests/replsets/db_reads_while_recovering_all_commands.js +++ b/jstests/replsets/db_reads_while_recovering_all_commands.js @@ -290,6 +290,7 @@ const allCommands = { startRecordingTraffic: {skip: isNotAUserDataRead}, startSession: {skip: isNotAUserDataRead}, stopRecordingTraffic: {skip: isNotAUserDataRead}, + testDeprecation: {skip: isNotAUserDataRead}, top: {skip: isNotAUserDataRead}, unsetSharding: {skip: isNotAUserDataRead}, update: {skip: isPrimaryOnly}, diff --git a/jstests/sharding/database_versioning_all_commands.js b/jstests/sharding/database_versioning_all_commands.js index f0db7782f84..f5bac9df015 100644 --- a/jstests/sharding/database_versioning_all_commands.js +++ b/jstests/sharding/database_versioning_all_commands.js @@ -626,6 +626,7 @@ let testCases = { startRecordingTraffic: {skip: "executes locally on mongos (not sent to any remote node)"}, startSession: {skip: "executes locally on mongos (not sent to any remote node)"}, stopRecordingTraffic: {skip: "executes locally on mongos (not sent to any remote node)"}, + testDeprecation: {skip: "executes locally on mongos (not sent to any remote node)"}, update: { run: { sendsDbVersion: true, diff --git a/jstests/sharding/libs/last_lts_mongos_commands.js b/jstests/sharding/libs/last_lts_mongos_commands.js index 0eda44d4ad7..d8e2c6cc4ff 100644 --- a/jstests/sharding/libs/last_lts_mongos_commands.js +++ b/jstests/sharding/libs/last_lts_mongos_commands.js @@ -7,4 +7,5 @@ const commandsRemovedFromMongosSinceLastLTS = []; // These commands were added in mongos since the last LTS version, so will not appear in the // listCommands output of a last LTS version mongos. We will allow these commands to have a test // defined without always existing on the mongos being used. -const commandsAddedToMongosSinceLastLTS = ["reshardCollection", "rotateCertificates"]; +const commandsAddedToMongosSinceLastLTS = + ["reshardCollection", "rotateCertificates", "testDeprecation"]; diff --git a/jstests/sharding/read_write_concern_defaults_application.js b/jstests/sharding/read_write_concern_defaults_application.js index d95cdd6eec7..40b76f35a48 100644 --- a/jstests/sharding/read_write_concern_defaults_application.js +++ b/jstests/sharding/read_write_concern_defaults_application.js @@ -615,6 +615,7 @@ let testCases = { startRecordingTraffic: {skip: "does not accept read or write concern"}, startSession: {skip: "does not accept read or write concern"}, stopRecordingTraffic: {skip: "does not accept read or write concern"}, + testDeprecation: {skip: "does not accept read or write concern"}, top: {skip: "does not accept read or write concern"}, unsetSharding: {skip: "internal command"}, update: { diff --git a/jstests/sharding/safe_secondary_reads_drop_recreate.js b/jstests/sharding/safe_secondary_reads_drop_recreate.js index e783c2098ec..6a03af25df7 100644 --- a/jstests/sharding/safe_secondary_reads_drop_recreate.js +++ b/jstests/sharding/safe_secondary_reads_drop_recreate.js @@ -297,6 +297,7 @@ let testCases = { startRecordingTraffic: {skip: "does not return user data"}, startSession: {skip: "does not return user data"}, stopRecordingTraffic: {skip: "does not return user data"}, + testDeprecation: {skip: "does not return user data"}, top: {skip: "does not return user data"}, unsetSharding: {skip: "does not return user data"}, update: {skip: "primary only"}, diff --git a/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js b/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js index 5792fcec8b8..260de634468 100644 --- a/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js +++ b/jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js @@ -369,6 +369,7 @@ let testCases = { startRecordingTraffic: {skip: "does not return user data"}, startSession: {skip: "does not return user data"}, stopRecordingTraffic: {skip: "does not return user data"}, + testDeprecation: {skip: "does not return user data"}, top: {skip: "does not return user data"}, unsetSharding: {skip: "does not return user data"}, update: {skip: "primary only"}, diff --git a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js index 0dbd9b93ca9..c502137fc03 100644 --- a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js +++ b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js @@ -304,6 +304,7 @@ let testCases = { startRecordingTraffic: {skip: "does not return user data"}, startSession: {skip: "does not return user data"}, stopRecordingTraffic: {skip: "does not return user data"}, + testDeprecation: {skip: "does not return user data"}, top: {skip: "does not return user data"}, unsetSharding: {skip: "does not return user data"}, update: {skip: "primary only"}, diff --git a/src/mongo/db/auth/sasl_commands.cpp b/src/mongo/db/auth/sasl_commands.cpp index 3e2b9e26f42..7f4b1010462 100644 --- a/src/mongo/db/auth/sasl_commands.cpp +++ b/src/mongo/db/auth/sasl_commands.cpp @@ -70,6 +70,10 @@ public: CmdSaslStart(); virtual ~CmdSaslStart(); + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + virtual void addRequiredPrivileges(const std::string&, const BSONObj&, std::vector<Privilege>*) const {} @@ -100,6 +104,9 @@ public: CmdSaslContinue(); virtual ~CmdSaslContinue(); + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } virtual void addRequiredPrivileges(const std::string&, const BSONObj&, std::vector<Privilege>*) const {} diff --git a/src/mongo/db/command_generic_argument.cpp b/src/mongo/db/command_generic_argument.cpp index 37ff2323e9f..86e6f6c0196 100644 --- a/src/mongo/db/command_generic_argument.cpp +++ b/src/mongo/db/command_generic_argument.cpp @@ -52,10 +52,13 @@ struct SpecialArgRecord { // If that changes, it should be added. When you add to this list, consider whether you // should also change the filterCommandRequestForPassthrough() function. // clang-format off -static constexpr std::array<SpecialArgRecord, 31> specials{{ +static constexpr std::array<SpecialArgRecord, 34> specials{{ // /-isGeneric // | /-stripFromRequest // | | /-stripFromReply + {"apiVersion"_sd, 1, 0, 0}, + {"apiStrict"_sd, 1, 0, 0}, + {"apiDeprecationErrors"_sd, 1, 0, 0}, {"$audit"_sd, 1, 1, 0}, {"$client"_sd, 1, 1, 0}, {"$configServerState"_sd, 1, 1, 1}, diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index c029cf9febe..6a07d0404be 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -358,12 +358,12 @@ public: // List of API versions that include this command. virtual const std::set<std::string>& apiVersions() const { return kNoApiVersions; - }; + } // API versions in which this command is deprecated. virtual const std::set<std::string>& deprecatedApiVersions() const { return kNoApiVersions; - }; + } /** * Like adminOnly, but even stricter: we must either be authenticated for admin db, diff --git a/src/mongo/db/commands/SConscript b/src/mongo/db/commands/SConscript index 910b0d7b88c..a4a1ebdc4ca 100644 --- a/src/mongo/db/commands/SConscript +++ b/src/mongo/db/commands/SConscript @@ -148,6 +148,7 @@ env.Library( 'logical_session_server_status_section.cpp', 'mr_common.cpp', 'reap_logical_session_cache_now.cpp', + 'test_deprecation_command.cpp', 'traffic_recording_cmds.cpp', 'user_management_commands_common.cpp', env.Idlc('drop_connections.idl')[0], @@ -171,6 +172,7 @@ env.Library( '$BUILD_DIR/mongo/db/repl/isself', '$BUILD_DIR/mongo/db/repl/repl_coordinator_interface', '$BUILD_DIR/mongo/db/session_catalog', + '$BUILD_DIR/mongo/db/shared_request_handling', '$BUILD_DIR/mongo/db/traffic_recorder', '$BUILD_DIR/mongo/executor/egress_tag_closer_manager', '$BUILD_DIR/mongo/executor/task_executor_pool', diff --git a/src/mongo/db/commands/authentication_commands.cpp b/src/mongo/db/commands/authentication_commands.cpp index f146e0c8742..77f014207fb 100644 --- a/src/mongo/db/commands/authentication_commands.cpp +++ b/src/mongo/db/commands/authentication_commands.cpp @@ -144,6 +144,10 @@ Status _authenticateX509(OperationContext* opCtx, const UserName& user, const BS class CmdAuthenticate : public BasicCommand { public: + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } diff --git a/src/mongo/db/commands/count_cmd.cpp b/src/mongo/db/commands/count_cmd.cpp index 6165ef9cdb5..fe8c4af8198 100644 --- a/src/mongo/db/commands/count_cmd.cpp +++ b/src/mongo/db/commands/count_cmd.cpp @@ -63,6 +63,10 @@ class CmdCount : public BasicCommand { public: CmdCount() : BasicCommand("count") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + std::string help() const override { return "count objects in collection"; } diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp index 5794fb26436..0a9e6c50e56 100644 --- a/src/mongo/db/commands/create_indexes.cpp +++ b/src/mongo/db/commands/create_indexes.cpp @@ -711,6 +711,10 @@ class CmdCreateIndex : public ErrmsgCommandDeprecated { public: CmdCreateIndex() : ErrmsgCommandDeprecated(kCommandName) {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + bool supportsWriteConcern(const BSONObj& cmd) const override { return true; } diff --git a/src/mongo/db/commands/dbcommands.cpp b/src/mongo/db/commands/dbcommands.cpp index 1fc8ae226a7..d1addd57762 100644 --- a/src/mongo/db/commands/dbcommands.cpp +++ b/src/mongo/db/commands/dbcommands.cpp @@ -105,6 +105,10 @@ namespace { class CmdDropDatabase : public BasicCommand { public: + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + std::string help() const override { return "drop (delete) this database"; } @@ -204,6 +208,11 @@ public: class CmdDrop : public ErrmsgCommandDeprecated { public: CmdDrop() : ErrmsgCommandDeprecated("drop") {} + + virtual const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } @@ -266,6 +275,10 @@ class CmdCreate : public BasicCommand { public: CmdCreate() : BasicCommand("create") {} + virtual const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } @@ -635,6 +648,10 @@ class CollectionModCommand : public BasicCommand { public: CollectionModCommand() : BasicCommand("collMod") {} + virtual const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } diff --git a/src/mongo/db/commands/drop_indexes.cpp b/src/mongo/db/commands/drop_indexes.cpp index 19eb43b32fa..cb6cc68f5f5 100644 --- a/src/mongo/db/commands/drop_indexes.cpp +++ b/src/mongo/db/commands/drop_indexes.cpp @@ -68,9 +68,14 @@ MONGO_FAIL_POINT_DEFINE(reIndexCrashAfterDrop); /* "dropIndexes" is now the preferred form - "deleteIndexes" deprecated */ class CmdDropIndexes : public BasicCommand { public: + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } + virtual bool supportsWriteConcern(const BSONObj& cmd) const override { return true; } diff --git a/src/mongo/db/commands/end_sessions_command.cpp b/src/mongo/db/commands/end_sessions_command.cpp index 15c19f907d8..d081c6d9874 100644 --- a/src/mongo/db/commands/end_sessions_command.cpp +++ b/src/mongo/db/commands/end_sessions_command.cpp @@ -48,6 +48,10 @@ class EndSessionsCommand final : public BasicCommand { public: EndSessionsCommand() : BasicCommand("endSessions") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } diff --git a/src/mongo/db/commands/explain_cmd.cpp b/src/mongo/db/commands/explain_cmd.cpp index 5cc8bc330c8..c3e1dff02e4 100644 --- a/src/mongo/db/commands/explain_cmd.cpp +++ b/src/mongo/db/commands/explain_cmd.cpp @@ -53,6 +53,10 @@ class CmdExplain final : public Command { public: CmdExplain() : Command("explain") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + std::unique_ptr<CommandInvocation> parse(OperationContext* opCtx, const OpMsgRequest& request) override; diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp index 143a0d4f593..9785b5b51e2 100644 --- a/src/mongo/db/commands/find_and_modify.cpp +++ b/src/mongo/db/commands/find_and_modify.cpp @@ -216,6 +216,10 @@ public: CmdFindAndModify() : BasicCommand("findAndModify", "findandmodify"), _updateMetrics{"findAndModify"} {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + std::string help() const override { return "{ findAndModify: \"collection\", query: {processed:false}, update: {$set: " "{processed:true}}, new: true}\n" diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp index 84501a9cbb7..517fb24bd54 100644 --- a/src/mongo/db/commands/find_cmd.cpp +++ b/src/mongo/db/commands/find_cmd.cpp @@ -128,6 +128,10 @@ class FindCmd final : public Command { public: FindCmd() : Command("find") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + std::unique_ptr<CommandInvocation> parse(OperationContext* opCtx, const OpMsgRequest& opMsgRequest) override { // TODO: Parse into a QueryRequest here. diff --git a/src/mongo/db/commands/generic.cpp b/src/mongo/db/commands/generic.cpp index 0296b180f05..1a52d0f7bfa 100644 --- a/src/mongo/db/commands/generic.cpp +++ b/src/mongo/db/commands/generic.cpp @@ -52,6 +52,10 @@ class PingCommand : public BasicCommand { public: PingCommand() : BasicCommand("ping") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } diff --git a/src/mongo/db/commands/getmore_cmd.cpp b/src/mongo/db/commands/getmore_cmd.cpp index 33f731e7cde..ba9947b3e7e 100644 --- a/src/mongo/db/commands/getmore_cmd.cpp +++ b/src/mongo/db/commands/getmore_cmd.cpp @@ -241,6 +241,12 @@ class GetMoreCmd final : public Command { public: GetMoreCmd() : Command("getMore") {} + // Do not currently use apiVersions because clients are prohibited from calling + // getMore with apiVersion. + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + std::unique_ptr<CommandInvocation> parse(OperationContext* opCtx, const OpMsgRequest& opMsgRequest) override { return std::make_unique<Invocation>(this, opMsgRequest); diff --git a/src/mongo/db/commands/killcursors_cmd.cpp b/src/mongo/db/commands/killcursors_cmd.cpp index 4604a83cfa2..9acf3b85b31 100644 --- a/src/mongo/db/commands/killcursors_cmd.cpp +++ b/src/mongo/db/commands/killcursors_cmd.cpp @@ -48,6 +48,10 @@ class KillCursorsCmd final : public KillCursorsCmdBase { public: KillCursorsCmd() = default; + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + bool run(OperationContext* opCtx, const std::string& dbname, const BSONObj& cmdObj, diff --git a/src/mongo/db/commands/list_collections.cpp b/src/mongo/db/commands/list_collections.cpp index ffe9956f205..e90b0eeed4d 100644 --- a/src/mongo/db/commands/list_collections.cpp +++ b/src/mongo/db/commands/list_collections.cpp @@ -212,6 +212,9 @@ BSONObj buildCollectionBson(OperationContext* opCtx, class CmdListCollections : public BasicCommand { public: + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } AllowedOnSecondary secondaryAllowed(ServiceContext*) const final { return AllowedOnSecondary::kOptIn; } diff --git a/src/mongo/db/commands/list_databases.cpp b/src/mongo/db/commands/list_databases.cpp index c656355ec06..9da849e8cae 100644 --- a/src/mongo/db/commands/list_databases.cpp +++ b/src/mongo/db/commands/list_databases.cpp @@ -62,6 +62,10 @@ intmax_t dbSize(const string& database); class CmdListDatabases : public BasicCommand { public: + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const final { return AllowedOnSecondary::kOptIn; } diff --git a/src/mongo/db/commands/list_indexes.cpp b/src/mongo/db/commands/list_indexes.cpp index 219cd2926f6..15e8bb52420 100644 --- a/src/mongo/db/commands/list_indexes.cpp +++ b/src/mongo/db/commands/list_indexes.cpp @@ -93,6 +93,10 @@ class CmdListIndexes : public BasicCommand { public: CmdListIndexes() : BasicCommand("listIndexes") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kOptIn; } diff --git a/src/mongo/db/commands/pipeline_command.cpp b/src/mongo/db/commands/pipeline_command.cpp index 915457281fe..6b542b421ae 100644 --- a/src/mongo/db/commands/pipeline_command.cpp +++ b/src/mongo/db/commands/pipeline_command.cpp @@ -43,6 +43,10 @@ class PipelineCommand final : public Command { public: PipelineCommand() : Command("aggregate") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + /** * It's not known until after parsing whether or not an aggregation command is an explain * request, because it might include the `explain: true` field (ie. aggregation explains do not diff --git a/src/mongo/db/commands/refresh_sessions_command.cpp b/src/mongo/db/commands/refresh_sessions_command.cpp index 6c177f743f1..0d8a96d4358 100644 --- a/src/mongo/db/commands/refresh_sessions_command.cpp +++ b/src/mongo/db/commands/refresh_sessions_command.cpp @@ -45,6 +45,10 @@ class RefreshSessionsCommand final : public BasicCommand { public: RefreshSessionsCommand() : BasicCommand("refreshSessions") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } diff --git a/src/mongo/db/commands/test_deprecation_command.cpp b/src/mongo/db/commands/test_deprecation_command.cpp new file mode 100644 index 00000000000..2ec6060bbe3 --- /dev/null +++ b/src/mongo/db/commands/test_deprecation_command.cpp @@ -0,0 +1,85 @@ +/** + * Copyright (C) 2020-present MongoDB, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the Server Side Public License, version 1, + * as published by MongoDB, Inc. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * Server Side Public License for more details. + * + * You should have received a copy of the Server Side Public License + * along with this program. If not, see + * <http://www.mongodb.com/licensing/server-side-public-license>. + * + * As a special exception, the copyright holders give permission to link the + * code of portions of this program with the OpenSSL library under certain + * conditions as described in each individual source file and distribute + * linked combinations including the program with the OpenSSL library. You + * must comply with the Server Side Public License in all respects for + * all of the code used other than as permitted herein. If you modify file(s) + * with this exception, you may extend this exception to your version of the + * file(s), but you are not obligated to do so. If you do not wish to do so, + * delete this exception statement from your version. If you delete this + * exception statement from all source files in the program, then also delete + * it in the license file. + */ + +#include "mongo/db/commands.h" +#include "mongo/db/initialize_api_parameters.h" + +namespace mongo { + +/** + * Command for testing API Version deprecation logic. The command replies with the values of the + * OperationContext's API parameters. + */ +class TestDeprecationCmd : public BasicCommand { +public: + TestDeprecationCmd() : BasicCommand("testDeprecation") {} + + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + + const std::set<std::string>& deprecatedApiVersions() const { + return kApiVersions1; + } + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + + bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + + bool requiresAuth() const override { + return false; + } + + void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) const override {} + + std::string help() const override { + return "replies with the values of the OperationContext's API parameters"; + } + + bool run(OperationContext* opCtx, + const std::string& dbname, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { + result.append("apiVersion", APIParameters::get(opCtx).getAPIVersion()); + result.append("apiStrict", APIParameters::get(opCtx).getAPIStrict()); + result.append("apiDeprecationErrors", APIParameters::get(opCtx).getAPIDeprecationErrors()); + return true; + } +}; + +MONGO_REGISTER_TEST_COMMAND(TestDeprecationCmd); + + +} // namespace mongo
\ No newline at end of file diff --git a/src/mongo/db/commands/txn_cmds.cpp b/src/mongo/db/commands/txn_cmds.cpp index 29e76b6ffce..df7aa9787dc 100644 --- a/src/mongo/db/commands/txn_cmds.cpp +++ b/src/mongo/db/commands/txn_cmds.cpp @@ -61,6 +61,10 @@ class CmdCommitTxn : public BasicCommand { public: CmdCommitTxn() : BasicCommand("commitTransaction") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } @@ -161,6 +165,10 @@ class CmdAbortTxn : public BasicCommand { public: CmdAbortTxn() : BasicCommand("abortTransaction") {} + virtual const std::set<std::string>& apiVersions() const { + return kApiVersions1; + }; + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp index a78a7318f60..8c0d4e0549d 100644 --- a/src/mongo/db/commands/write_commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands/write_commands.cpp @@ -286,6 +286,10 @@ class CmdInsert final : public WriteCommand { public: CmdInsert() : WriteCommand("insert") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + private: class Invocation final : public InvocationBase { public: @@ -332,6 +336,10 @@ class CmdUpdate final : public WriteCommand { public: CmdUpdate() : WriteCommand("update"), _updateMetrics{"update"} {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + private: class Invocation final : public InvocationBase { public: @@ -486,12 +494,17 @@ class CmdDelete final : public WriteCommand { public: CmdDelete() : WriteCommand("delete") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + private: class Invocation final : public InvocationBase { public: Invocation(const WriteCommand* cmd, const OpMsgRequest& request) : InvocationBase(cmd, request), _batch(DeleteOp::parse(request)) {} + private: NamespaceString ns() const override { return _batch.getNamespace(); diff --git a/src/mongo/db/initialize_api_parameters.cpp b/src/mongo/db/initialize_api_parameters.cpp index c78f1d130f4..ed7245d7d41 100644 --- a/src/mongo/db/initialize_api_parameters.cpp +++ b/src/mongo/db/initialize_api_parameters.cpp @@ -31,7 +31,8 @@ namespace mongo { -const APIParametersFromClient initializeAPIParameters(const BSONObj& requestBody) { +const APIParametersFromClient initializeAPIParameters(const BSONObj& requestBody, + Command* command) { auto apiParamsFromClient = APIParametersFromClient::parse("APIParametersFromClient"_sd, requestBody); @@ -48,6 +49,24 @@ const APIParametersFromClient initializeAPIParameters(const BSONObj& requestBody "1" == apiParamsFromClient.getApiVersion().value()); } + if (apiParamsFromClient.getApiStrict().get_value_or(false)) { + auto cmdApiVersions = command->apiVersions(); + bool strictAssert = (cmdApiVersions.find("1") != cmdApiVersions.end()); + uassert(ErrorCodes::APIStrictError, + str::stream() << "Provided apiStrict:true, but the command " << command->getName() + << " is not in API Version \"1\"", + strictAssert); + } + + if (apiParamsFromClient.getApiDeprecationErrors().get_value_or(false)) { + auto cmdDepApiVersions = command->deprecatedApiVersions(); + bool deprecationAssert = (cmdDepApiVersions.find("1") == cmdDepApiVersions.end()); + uassert(ErrorCodes::APIDeprecationError, + str::stream() << "Provided apiDeprecationErrors:true, but the command " + << command->getName() << " is deprecated in API Version \"1\"", + deprecationAssert); + } + return apiParamsFromClient; } diff --git a/src/mongo/db/initialize_api_parameters.h b/src/mongo/db/initialize_api_parameters.h index a8c1ee141e4..9e6aac0c31a 100644 --- a/src/mongo/db/initialize_api_parameters.h +++ b/src/mongo/db/initialize_api_parameters.h @@ -29,6 +29,7 @@ #pragma once +#include "mongo/db/commands.h" #include "mongo/db/initialize_api_parameters_gen.h" #include "mongo/db/operation_context.h" @@ -38,7 +39,7 @@ namespace mongo { * Parses a command's API Version parameters from a request and stores the apiVersion, apiStrict, * and apiDeprecationErrors fields. */ -const APIParametersFromClient initializeAPIParameters(const BSONObj& requestBody); +const APIParametersFromClient initializeAPIParameters(const BSONObj& requestBody, Command* command); /** * Decorates operation context with methods to retrieve apiVersion, apiStrict, and diff --git a/src/mongo/db/repl/replication_info.cpp b/src/mongo/db/repl/replication_info.cpp index c6c0c331920..6350ffea81d 100644 --- a/src/mongo/db/repl/replication_info.cpp +++ b/src/mongo/db/repl/replication_info.cpp @@ -225,6 +225,10 @@ class CmdIsMaster final : public BasicCommandWithReplyBuilderInterface { public: CmdIsMaster() : BasicCommandWithReplyBuilderInterface("isMaster", "ismaster") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + bool requiresAuth() const final { return false; } diff --git a/src/mongo/db/s/config/configsvr_drop_collection_command.cpp b/src/mongo/db/s/config/configsvr_drop_collection_command.cpp index 77cf249fd41..fc74fafc0c5 100644 --- a/src/mongo/db/s/config/configsvr_drop_collection_command.cpp +++ b/src/mongo/db/s/config/configsvr_drop_collection_command.cpp @@ -59,6 +59,10 @@ class ConfigSvrDropCollectionCommand : public BasicCommand { public: ConfigSvrDropCollectionCommand() : BasicCommand("_configsvrDropCollection") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } diff --git a/src/mongo/db/s/config/configsvr_drop_database_command.cpp b/src/mongo/db/s/config/configsvr_drop_database_command.cpp index 56aa8db1d94..eb3ef547e70 100644 --- a/src/mongo/db/s/config/configsvr_drop_database_command.cpp +++ b/src/mongo/db/s/config/configsvr_drop_database_command.cpp @@ -54,6 +54,10 @@ class ConfigSvrDropDatabaseCommand : public BasicCommand { public: ConfigSvrDropDatabaseCommand() : BasicCommand("_configsvrDropDatabase") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } diff --git a/src/mongo/db/service_entry_point_common.cpp b/src/mongo/db/service_entry_point_common.cpp index e8c6f5808e4..d1554581e13 100644 --- a/src/mongo/db/service_entry_point_common.cpp +++ b/src/mongo/db/service_entry_point_common.cpp @@ -945,7 +945,7 @@ void execCommandDatabase(OperationContext* opCtx, auto const replCoord = repl::ReplicationCoordinator::get(opCtx); - auto const apiParamsFromClient = initializeAPIParameters(request.body); + auto const apiParamsFromClient = initializeAPIParameters(request.body, command); APIParameters::get(opCtx) = APIParameters::fromClient(apiParamsFromClient); sessionOptions = initializeOperationSessionInfo( diff --git a/src/mongo/embedded/mongo_embedded/mongo_embedded_test.cpp b/src/mongo/embedded/mongo_embedded/mongo_embedded_test.cpp index 6ab5108ae51..ab600e89e15 100644 --- a/src/mongo/embedded/mongo_embedded/mongo_embedded_test.cpp +++ b/src/mongo/embedded/mongo_embedded/mongo_embedded_test.cpp @@ -600,6 +600,7 @@ TEST_F(MongodbCAPITest, RunListCommands) { "setParameter", "sleep", "startSession", + "testDeprecation", "update", "validate", "waitForFailPoint", diff --git a/src/mongo/s/commands/cluster_abort_transaction_cmd.cpp b/src/mongo/s/commands/cluster_abort_transaction_cmd.cpp index a463e94854d..9259f9c108e 100644 --- a/src/mongo/s/commands/cluster_abort_transaction_cmd.cpp +++ b/src/mongo/s/commands/cluster_abort_transaction_cmd.cpp @@ -51,6 +51,10 @@ class ClusterAbortTransactionCmd : public BasicCommand { public: ClusterAbortTransactionCmd() : BasicCommand("abortTransaction") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } diff --git a/src/mongo/s/commands/cluster_collection_mod_cmd.cpp b/src/mongo/s/commands/cluster_collection_mod_cmd.cpp index 4c276f7d2e4..6296c71a8d6 100644 --- a/src/mongo/s/commands/cluster_collection_mod_cmd.cpp +++ b/src/mongo/s/commands/cluster_collection_mod_cmd.cpp @@ -44,6 +44,10 @@ class CollectionModCmd : public ErrmsgCommandDeprecated { public: CollectionModCmd() : ErrmsgCommandDeprecated("collMod") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } diff --git a/src/mongo/s/commands/cluster_commit_transaction_cmd.cpp b/src/mongo/s/commands/cluster_commit_transaction_cmd.cpp index 863113e17dd..bbcfccd0dee 100644 --- a/src/mongo/s/commands/cluster_commit_transaction_cmd.cpp +++ b/src/mongo/s/commands/cluster_commit_transaction_cmd.cpp @@ -46,6 +46,10 @@ class ClusterCommitTransactionCmd : public BasicCommand { public: ClusterCommitTransactionCmd() : BasicCommand("commitTransaction") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } diff --git a/src/mongo/s/commands/cluster_count_cmd.cpp b/src/mongo/s/commands/cluster_count_cmd.cpp index 7bc290de6ea..00e186d4d05 100644 --- a/src/mongo/s/commands/cluster_count_cmd.cpp +++ b/src/mongo/s/commands/cluster_count_cmd.cpp @@ -53,6 +53,10 @@ class ClusterCountCmd : public ErrmsgCommandDeprecated { public: ClusterCountCmd() : ErrmsgCommandDeprecated("count") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } diff --git a/src/mongo/s/commands/cluster_create_cmd.cpp b/src/mongo/s/commands/cluster_create_cmd.cpp index 2feaa027e8c..2a4f2fd7dab 100644 --- a/src/mongo/s/commands/cluster_create_cmd.cpp +++ b/src/mongo/s/commands/cluster_create_cmd.cpp @@ -45,6 +45,10 @@ class CreateCmd : public BasicCommand { public: CreateCmd() : BasicCommand("create") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } diff --git a/src/mongo/s/commands/cluster_create_indexes_cmd.cpp b/src/mongo/s/commands/cluster_create_indexes_cmd.cpp index 03fd5c28775..bd27780bb6c 100644 --- a/src/mongo/s/commands/cluster_create_indexes_cmd.cpp +++ b/src/mongo/s/commands/cluster_create_indexes_cmd.cpp @@ -44,6 +44,10 @@ class CreateIndexesCmd : public ErrmsgCommandDeprecated { public: CreateIndexesCmd() : ErrmsgCommandDeprecated("createIndexes") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kNever; } diff --git a/src/mongo/s/commands/cluster_drop_cmd.cpp b/src/mongo/s/commands/cluster_drop_cmd.cpp index 59a2fef563f..a69e3292597 100644 --- a/src/mongo/s/commands/cluster_drop_cmd.cpp +++ b/src/mongo/s/commands/cluster_drop_cmd.cpp @@ -46,6 +46,10 @@ class DropCmd : public BasicCommand { public: DropCmd() : BasicCommand("drop") {} + virtual const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } diff --git a/src/mongo/s/commands/cluster_drop_database_cmd.cpp b/src/mongo/s/commands/cluster_drop_database_cmd.cpp index 8610dc673d3..a78cb00fd79 100644 --- a/src/mongo/s/commands/cluster_drop_database_cmd.cpp +++ b/src/mongo/s/commands/cluster_drop_database_cmd.cpp @@ -46,6 +46,10 @@ class DropDatabaseCmd : public BasicCommand { public: DropDatabaseCmd() : BasicCommand("dropDatabase") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } diff --git a/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp b/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp index b26d3703db9..87ca9422a13 100644 --- a/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp +++ b/src/mongo/s/commands/cluster_drop_indexes_cmd.cpp @@ -71,6 +71,10 @@ void updateStateForStaleConfigRetry(OperationContext* opCtx, class DropIndexesCmd : public ErrmsgCommandDeprecated { public: + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + DropIndexesCmd() : ErrmsgCommandDeprecated("dropIndexes", "deleteIndexes") {} AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { diff --git a/src/mongo/s/commands/cluster_explain_cmd.cpp b/src/mongo/s/commands/cluster_explain_cmd.cpp index 9fd37a65c78..4d17e5ebd19 100644 --- a/src/mongo/s/commands/cluster_explain_cmd.cpp +++ b/src/mongo/s/commands/cluster_explain_cmd.cpp @@ -54,6 +54,10 @@ class ClusterExplainCmd final : public Command { public: ClusterExplainCmd() : Command("explain") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + std::unique_ptr<CommandInvocation> parse(OperationContext* opCtx, const OpMsgRequest& request) override; diff --git a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp index 17013526125..c8b52598c2d 100644 --- a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp @@ -170,6 +170,10 @@ public: FindAndModifyCmd() : BasicCommand("findAndModify", "findandmodify"), _updateMetrics{"findAndModify"} {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } diff --git a/src/mongo/s/commands/cluster_find_cmd.cpp b/src/mongo/s/commands/cluster_find_cmd.cpp index 51d6272400b..3bd8ff6c7c3 100644 --- a/src/mongo/s/commands/cluster_find_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_cmd.cpp @@ -85,6 +85,10 @@ class ClusterFindCmd final : public Command { public: ClusterFindCmd() : Command("find") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + std::unique_ptr<CommandInvocation> parse(OperationContext* opCtx, const OpMsgRequest& opMsgRequest) override { // TODO: Parse into a QueryRequest here. diff --git a/src/mongo/s/commands/cluster_getmore_cmd.cpp b/src/mongo/s/commands/cluster_getmore_cmd.cpp index fdc167d2cb7..037e278d1e3 100644 --- a/src/mongo/s/commands/cluster_getmore_cmd.cpp +++ b/src/mongo/s/commands/cluster_getmore_cmd.cpp @@ -58,6 +58,12 @@ class ClusterGetMoreCmd final : public Command { public: ClusterGetMoreCmd() : Command("getMore") {} + // Do not currently use apiVersions because clients are prohibited from calling + // getMore with apiVersion. + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + std::unique_ptr<CommandInvocation> parse(OperationContext* opCtx, const OpMsgRequest& opMsgRequest) override { return std::make_unique<Invocation>(this, opMsgRequest); diff --git a/src/mongo/s/commands/cluster_is_master_cmd.cpp b/src/mongo/s/commands/cluster_is_master_cmd.cpp index 778ec8aae17..cab3fca4f18 100644 --- a/src/mongo/s/commands/cluster_is_master_cmd.cpp +++ b/src/mongo/s/commands/cluster_is_master_cmd.cpp @@ -59,6 +59,10 @@ class CmdIsMaster : public BasicCommandWithReplyBuilderInterface { public: CmdIsMaster() : BasicCommandWithReplyBuilderInterface("isMaster", "ismaster") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } diff --git a/src/mongo/s/commands/cluster_killcursors_cmd.cpp b/src/mongo/s/commands/cluster_killcursors_cmd.cpp index 106a6f7f1d6..b02c3ebe2a3 100644 --- a/src/mongo/s/commands/cluster_killcursors_cmd.cpp +++ b/src/mongo/s/commands/cluster_killcursors_cmd.cpp @@ -42,6 +42,10 @@ class ClusterKillCursorsCmd final : public KillCursorsCmdBase { public: ClusterKillCursorsCmd() = default; + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + ReadConcernSupportResult supportsReadConcern(const BSONObj& cmdObj, repl::ReadConcernLevel level) const final { // killCursors must support read concerns in order to be run in transactions. diff --git a/src/mongo/s/commands/cluster_list_collections_cmd.cpp b/src/mongo/s/commands/cluster_list_collections_cmd.cpp index 255d4ec7453..a6adf99544b 100644 --- a/src/mongo/s/commands/cluster_list_collections_cmd.cpp +++ b/src/mongo/s/commands/cluster_list_collections_cmd.cpp @@ -160,6 +160,10 @@ class CmdListCollections : public BasicCommand { public: CmdListCollections() : BasicCommand("listCollections") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } diff --git a/src/mongo/s/commands/cluster_list_databases_cmd.cpp b/src/mongo/s/commands/cluster_list_databases_cmd.cpp index 4222656f498..5dea5e17120 100644 --- a/src/mongo/s/commands/cluster_list_databases_cmd.cpp +++ b/src/mongo/s/commands/cluster_list_databases_cmd.cpp @@ -51,6 +51,10 @@ class ListDatabasesCmd : public BasicCommand { public: ListDatabasesCmd() : BasicCommand("listDatabases", "listdatabases") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } diff --git a/src/mongo/s/commands/cluster_list_indexes_cmd.cpp b/src/mongo/s/commands/cluster_list_indexes_cmd.cpp index 56828a9ee95..8a4d93a3297 100644 --- a/src/mongo/s/commands/cluster_list_indexes_cmd.cpp +++ b/src/mongo/s/commands/cluster_list_indexes_cmd.cpp @@ -72,6 +72,10 @@ class CmdListIndexes : public BasicCommand { public: CmdListIndexes() : BasicCommand("listIndexes") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { return CommandHelpers::parseNsCollectionRequired(dbname, cmdObj).ns(); } diff --git a/src/mongo/s/commands/cluster_pipeline_cmd.cpp b/src/mongo/s/commands/cluster_pipeline_cmd.cpp index 7cca5f09c17..cbeb9022c43 100644 --- a/src/mongo/s/commands/cluster_pipeline_cmd.cpp +++ b/src/mongo/s/commands/cluster_pipeline_cmd.cpp @@ -45,6 +45,10 @@ class ClusterPipelineCommand final : public Command { public: ClusterPipelineCommand() : Command("aggregate") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + /** * It's not known until after parsing whether or not an aggregation command is an explain * request, because it might include the `explain: true` field (ie. aggregation explains do not diff --git a/src/mongo/s/commands/cluster_write_cmd.cpp b/src/mongo/s/commands/cluster_write_cmd.cpp index 24e98b9dced..17d1d415679 100644 --- a/src/mongo/s/commands/cluster_write_cmd.cpp +++ b/src/mongo/s/commands/cluster_write_cmd.cpp @@ -633,6 +633,10 @@ class ClusterInsertCmd final : public ClusterWriteCmd { public: ClusterInsertCmd() : ClusterWriteCmd("insert") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + private: class Invocation final : public InvocationBase { public: @@ -666,6 +670,10 @@ class ClusterUpdateCmd final : public ClusterWriteCmd { public: ClusterUpdateCmd() : ClusterWriteCmd("update"), _updateMetrics{"update"} {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + private: class Invocation final : public InvocationBase { public: @@ -705,6 +713,10 @@ class ClusterDeleteCmd final : public ClusterWriteCmd { public: ClusterDeleteCmd() : ClusterWriteCmd("delete") {} + const std::set<std::string>& apiVersions() const { + return kApiVersions1; + } + private: class Invocation final : public InvocationBase { public: diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp index 13373695a05..2b7607cfcdc 100644 --- a/src/mongo/s/commands/strategy.cpp +++ b/src/mongo/s/commands/strategy.cpp @@ -348,7 +348,7 @@ void runCommand(OperationContext* opCtx, // Fill out all currentOp details. CurOp::get(opCtx)->setGenericOpRequestDetails(opCtx, nss, command, request.body, opType); - auto const apiParamsFromClient = initializeAPIParameters(request.body); + auto const apiParamsFromClient = initializeAPIParameters(request.body, command); APIParameters::get(opCtx) = APIParameters::fromClient(apiParamsFromClient); auto osi = initializeOperationSessionInfo(opCtx, |