diff options
19 files changed, 125 insertions, 121 deletions
diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp index 52f2bc44c11..045a4c3715c 100644 --- a/src/mongo/db/commands.cpp +++ b/src/mongo/db/commands.cpp @@ -341,6 +341,25 @@ bool Command::enhancedRun(OperationContext* opCtx, return run(opCtx, request.getDatabase().toString(), request.body, errmsg, result); } +BSONObj Command::filterCommandRequestForPassthrough(const BSONObj& cmdObj) { + BSONObjBuilder bob; + for (auto elem : cmdObj) { + const auto name = elem.fieldNameStringData(); + if (name == "$readPreference") { + BSONObjBuilder(bob.subobjStart("$queryOptions")).append(elem); + } else if (!Command::isGenericArgument(name) || // + name == "$queryOptions" || // + name == "maxTimeMS" || // + name == "readConcern" || // + name == "writeConcern") { + // This is the whitelist of generic arguments that commands can be trusted to blindly + // forward to the shards. + bob.append(elem); + } + } + return bob.obj(); +} + void Command::filterCommandReplyForPassthrough(const BSONObj& cmdObj, BSONObjBuilder* output) { for (auto elem : cmdObj) { const auto name = elem.fieldNameStringData(); diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index 603ae5baa0f..6a7abae5879 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -496,7 +496,7 @@ public: static bool isGenericArgument(StringData arg) { // Not including "help" since we don't pass help requests through to the command parser. // If that changes, it should be added. When you add to this list, consider whether you - // should also change the filterCommandRequestForPassthrough() function in sharding. + // should also change the filterCommandRequestForPassthrough() function. return arg == "$audit" || // arg == "$client" || // arg == "$configServerState" || // @@ -515,6 +515,24 @@ public: } /** + * Rewrites cmdObj into a format safe to blindly forward to shards. + * + * This performs 2 transformations: + * 1) $readPreference fields are moved into a subobject called $queryOptions. This matches the + * "wrapped" format historically used internally by mongos. Moving off of that format will be + * done as SERVER-29091. + * + * 2) Filter out generic arguments that shouldn't be blindly passed to the shards. This is + * necessary because many mongos implementations of Command::run() just pass cmdObj through + * directly to the shards. However, some of the generic arguments fields are automatically + * appended in the egress layer. Removing them here ensures that they don't get duplicated. + * + * Ideally this function can be deleted once mongos run() implementations are more careful about + * what they send to the shards. + */ + static BSONObj filterCommandRequestForPassthrough(const BSONObj& cmdObj); + + /** * Rewrites reply into a format safe to blindly forward from shards to clients. * * Ideally this function can be deleted once mongos run() implementations are more careful about diff --git a/src/mongo/s/commands/cluster_aggregate.cpp b/src/mongo/s/commands/cluster_aggregate.cpp index a491ed5e553..5ab0184dfbd 100644 --- a/src/mongo/s/commands/cluster_aggregate.cpp +++ b/src/mongo/s/commands/cluster_aggregate.cpp @@ -450,6 +450,7 @@ Status ClusterAggregate::aggPassthrough(OperationContext* opCtx, cmdObj = explainCmdObj.toBson(); } + cmdObj = Command::filterCommandRequestForPassthrough(cmdObj); auto cmdResponse = uassertStatusOK(shard->runCommandWithFixedRetryAttempts( opCtx, ReadPreferenceSetting::get(opCtx), diff --git a/src/mongo/s/commands/cluster_current_op.cpp b/src/mongo/s/commands/cluster_current_op.cpp index ffc2a3fa067..df4c0b15132 100644 --- a/src/mongo/s/commands/cluster_current_op.cpp +++ b/src/mongo/s/commands/cluster_current_op.cpp @@ -85,8 +85,11 @@ public: const BSONObj& cmdObj, std::string& errmsg, BSONObjBuilder& output) override { - auto shardResponses = uassertStatusOK( - scatterGather(opCtx, dbName, cmdObj, ReadPreferenceSetting::get(opCtx))); + auto shardResponses = + uassertStatusOK(scatterGather(opCtx, + dbName, + filterCommandRequestForPassthrough(cmdObj), + ReadPreferenceSetting::get(opCtx))); if (!appendRawResponses(opCtx, &errmsg, &output, shardResponses)) { return false; } diff --git a/src/mongo/s/commands/cluster_db_stats_cmd.cpp b/src/mongo/s/commands/cluster_db_stats_cmd.cpp index 297638e424d..b1dcb07e491 100644 --- a/src/mongo/s/commands/cluster_db_stats_cmd.cpp +++ b/src/mongo/s/commands/cluster_db_stats_cmd.cpp @@ -68,8 +68,11 @@ public: const BSONObj& cmdObj, std::string& errmsg, BSONObjBuilder& output) override { - auto shardResponses = uassertStatusOK( - scatterGather(opCtx, dbName, cmdObj, ReadPreferenceSetting::get(opCtx))); + auto shardResponses = + uassertStatusOK(scatterGather(opCtx, + dbName, + filterCommandRequestForPassthrough(cmdObj), + ReadPreferenceSetting::get(opCtx))); if (!appendRawResponses(opCtx, &errmsg, &output, shardResponses)) { return false; } diff --git a/src/mongo/s/commands/cluster_explain.cpp b/src/mongo/s/commands/cluster_explain.cpp index 59f4ca83cc5..9970138748e 100644 --- a/src/mongo/s/commands/cluster_explain.cpp +++ b/src/mongo/s/commands/cluster_explain.cpp @@ -130,13 +130,14 @@ std::vector<Strategy::CommandResult> ClusterExplain::downconvert( // static BSONObj ClusterExplain::wrapAsExplain(const BSONObj& cmdObj, ExplainOptions::Verbosity verbosity) { + auto filtered = Command::filterCommandRequestForPassthrough(cmdObj); BSONObjBuilder out; - out.append("explain", cmdObj); + out.append("explain", filtered); out.append("verbosity", ExplainOptions::verbosityString(verbosity)); // Propagate all generic arguments out of the inner command since the shards will only process // them at the top level. - for (auto elem : cmdObj) { + for (auto elem : filtered) { if (Command::isGenericArgument(elem.fieldNameStringData())) { out.append(elem); } 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 6594ba534bf..33f10c478f5 100644 --- a/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_and_modify_cmd.cpp @@ -232,7 +232,8 @@ private: uassertStatusOK(Grid::get(opCtx)->shardRegistry()->getShard(opCtx, shardId)); ShardConnection conn(shard->getConnString(), nss.ns(), chunkManager); - bool ok = conn->runCommand(nss.db().toString(), cmdObj, res); + bool ok = + conn->runCommand(nss.db().toString(), filterCommandRequestForPassthrough(cmdObj), res); conn.done(); // ErrorCodes::RecvStaleConfig is the code for RecvStaleConfigException. diff --git a/src/mongo/s/commands/cluster_find_cmd.cpp b/src/mongo/s/commands/cluster_find_cmd.cpp index 16c84ab5c27..4bf8b053008 100644 --- a/src/mongo/s/commands/cluster_find_cmd.cpp +++ b/src/mongo/s/commands/cluster_find_cmd.cpp @@ -171,19 +171,12 @@ public: return appendCommandStatus(result, cq.getStatus()); } - // Extract read preference. If no read preference is specified in the query, will we pass - // down a "primaryOnly" or "secondary" read pref, depending on the slaveOk setting. - auto readPref = ClusterFind::extractUnwrappedReadPref(cmdObj); - if (!readPref.isOK()) { - return appendCommandStatus(result, readPref.getStatus()); - } - // Do the work to generate the first batch of results. This blocks waiting to get responses // from the shard(s). std::vector<BSONObj> batch; BSONObj viewDefinition; auto cursorId = ClusterFind::runQuery( - opCtx, *cq.getValue(), readPref.getValue(), &batch, &viewDefinition); + opCtx, *cq.getValue(), ReadPreferenceSetting::get(opCtx), &batch, &viewDefinition); if (!cursorId.isOK()) { if (cursorId.getStatus() == ErrorCodes::CommandOnShardedViewNotSupportedOnMongod) { auto aggCmdOnView = cq.getValue()->getQueryRequest().asAggregationCommand(); diff --git a/src/mongo/s/commands/cluster_get_last_error_cmd.cpp b/src/mongo/s/commands/cluster_get_last_error_cmd.cpp index 4d366c1a1de..57e036562eb 100644 --- a/src/mongo/s/commands/cluster_get_last_error_cmd.cpp +++ b/src/mongo/s/commands/cluster_get_last_error_cmd.cpp @@ -243,7 +243,8 @@ public: const HostOpTimeMap hostOpTimes(ClusterLastErrorInfo::get(cc())->getPrevHostOpTimes()); std::vector<LegacyWCResponse> wcResponses; - auto status = enforceLegacyWriteConcern(opCtx, dbname, cmdObj, hostOpTimes, &wcResponses); + auto status = enforceLegacyWriteConcern( + opCtx, dbname, filterCommandRequestForPassthrough(cmdObj), hostOpTimes, &wcResponses); // Don't forget about our last hosts, reset the client info ClusterLastErrorInfo::get(cc())->disableForCommand(); diff --git a/src/mongo/s/commands/cluster_index_filter_cmd.cpp b/src/mongo/s/commands/cluster_index_filter_cmd.cpp index 23328fa3f18..7b7ef05ef22 100644 --- a/src/mongo/s/commands/cluster_index_filter_cmd.cpp +++ b/src/mongo/s/commands/cluster_index_filter_cmd.cpp @@ -106,8 +106,13 @@ public: // commands are tied to query shape (data has no effect on query shape). vector<Strategy::CommandResult> results; const BSONObj query; - Strategy::commandOp( - opCtx, dbname, cmdObj, nss.ns(), query, CollationSpec::kSimpleSpec, &results); + Strategy::commandOp(opCtx, + dbname, + filterCommandRequestForPassthrough(cmdObj), + nss.ns(), + query, + CollationSpec::kSimpleSpec, + &results); // Set value of first shard result's "ok" field. bool clusterCmdResult = true; diff --git a/src/mongo/s/commands/cluster_list_databases_cmd.cpp b/src/mongo/s/commands/cluster_list_databases_cmd.cpp index 68c9cd55581..bc81d7f5b8d 100644 --- a/src/mongo/s/commands/cluster_list_databases_cmd.cpp +++ b/src/mongo/s/commands/cluster_list_databases_cmd.cpp @@ -39,6 +39,7 @@ #include "mongo/s/catalog/sharding_catalog_client.h" #include "mongo/s/client/shard.h" #include "mongo/s/client/shard_registry.h" +#include "mongo/s/commands/strategy.h" #include "mongo/s/grid.h" namespace mongo { @@ -107,7 +108,7 @@ public: opCtx, ReadPreferenceSetting{ReadPreference::PrimaryPreferred}, "admin", - cmdObj, + filterCommandRequestForPassthrough(cmdObj), Shard::RetryPolicy::kIdempotent)); uassertStatusOK(response.commandStatus); BSONObj x = std::move(response.response); @@ -166,14 +167,14 @@ public: // Get information for config and admin dbs from the config servers. auto catalogClient = grid.catalogClient(opCtx); - auto appendStatus = - catalogClient->appendInfoForConfigServerDatabases(opCtx, cmdObj, &dbListBuilder); + auto appendStatus = catalogClient->appendInfoForConfigServerDatabases( + opCtx, filterCommandRequestForPassthrough(cmdObj), &dbListBuilder); + dbListBuilder.doneFast(); if (!appendStatus.isOK()) { + result.resetToEmpty(); return Command::appendCommandStatus(result, appendStatus); } - dbListBuilder.done(); - if (nameOnly) return true; diff --git a/src/mongo/s/commands/cluster_map_reduce_cmd.cpp b/src/mongo/s/commands/cluster_map_reduce_cmd.cpp index 3e9cd98da85..858f5c09dfa 100644 --- a/src/mongo/s/commands/cluster_map_reduce_cmd.cpp +++ b/src/mongo/s/commands/cluster_map_reduce_cmd.cpp @@ -282,7 +282,7 @@ public: ShardConnection conn(inputRoutingInfo.primary()->getConnString(), ""); BSONObj res; - bool ok = conn->runCommand(dbname, cmdObj, res); + bool ok = conn->runCommand(dbname, filterCommandRequestForPassthrough(cmdObj), res); conn.done(); if (auto wcErrorElem = res["writeConcernError"]) { diff --git a/src/mongo/s/commands/cluster_plan_cache_cmd.cpp b/src/mongo/s/commands/cluster_plan_cache_cmd.cpp index 3ca3798a929..775dd7b3aec 100644 --- a/src/mongo/s/commands/cluster_plan_cache_cmd.cpp +++ b/src/mongo/s/commands/cluster_plan_cache_cmd.cpp @@ -121,8 +121,13 @@ bool ClusterPlanCacheCmd::run(OperationContext* opCtx, // commands are tied to query shape (data has no effect on query shape). vector<Strategy::CommandResult> results; const BSONObj query; - Strategy::commandOp( - opCtx, dbName, cmdObj, nss.ns(), query, CollationSpec::kSimpleSpec, &results); + Strategy::commandOp(opCtx, + dbName, + filterCommandRequestForPassthrough(cmdObj), + nss.ns(), + query, + CollationSpec::kSimpleSpec, + &results); // Set value of first shard result's "ok" field. bool clusterCmdResult = true; diff --git a/src/mongo/s/commands/cluster_reset_error_cmd.cpp b/src/mongo/s/commands/cluster_reset_error_cmd.cpp index 7844ac44a27..8757e8944a6 100644 --- a/src/mongo/s/commands/cluster_reset_error_cmd.cpp +++ b/src/mongo/s/commands/cluster_reset_error_cmd.cpp @@ -76,7 +76,7 @@ public: BSONObj res; // Don't care about result from shards. - conn->runCommand(dbname, cmdObj, res); + conn->runCommand(dbname, filterCommandRequestForPassthrough(cmdObj), res); conn.done(); } diff --git a/src/mongo/s/commands/cluster_user_management_commands.cpp b/src/mongo/s/commands/cluster_user_management_commands.cpp index dfa2233c57f..72c4d04868c 100644 --- a/src/mongo/s/commands/cluster_user_management_commands.cpp +++ b/src/mongo/s/commands/cluster_user_management_commands.cpp @@ -92,7 +92,7 @@ public: string& errmsg, BSONObjBuilder& result) { return Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); } virtual void redactForLogging(mutablebson::Document* cmdObj) { @@ -135,7 +135,7 @@ public: return appendCommandStatus(result, status); } const bool ok = Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); @@ -184,7 +184,7 @@ public: return appendCommandStatus(result, status); } const bool ok = Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); @@ -224,7 +224,7 @@ public: string& errmsg, BSONObjBuilder& result) { const bool ok = Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); @@ -271,7 +271,7 @@ public: return appendCommandStatus(result, status); } const bool ok = Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); @@ -318,7 +318,7 @@ public: return appendCommandStatus(result, status); } const bool ok = Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); @@ -362,7 +362,7 @@ public: string& errmsg, BSONObjBuilder& result) { return Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementReadCommand( - opCtx, dbname, cmdObj, &result); + opCtx, dbname, filterCommandRequestForPassthrough(cmdObj), &result); } } cmdUsersInfo; @@ -396,7 +396,7 @@ public: string& errmsg, BSONObjBuilder& result) { return Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); } } cmdCreateRole; @@ -430,7 +430,7 @@ public: string& errmsg, BSONObjBuilder& result) { const bool ok = Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); @@ -470,7 +470,7 @@ public: string& errmsg, BSONObjBuilder& result) { const bool ok = Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); @@ -510,7 +510,7 @@ public: string& errmsg, BSONObjBuilder& result) { const bool ok = Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); @@ -550,7 +550,7 @@ public: string& errmsg, BSONObjBuilder& result) { const bool ok = Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); @@ -590,7 +590,7 @@ public: string& errmsg, BSONObjBuilder& result) { const bool ok = Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); @@ -633,7 +633,7 @@ public: string& errmsg, BSONObjBuilder& result) { const bool ok = Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); @@ -677,7 +677,7 @@ public: string& errmsg, BSONObjBuilder& result) { const bool ok = Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); AuthorizationManager* authzManager = getGlobalAuthorizationManager(); invariant(authzManager); @@ -721,7 +721,7 @@ public: string& errmsg, BSONObjBuilder& result) { return Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementReadCommand( - opCtx, dbname, cmdObj, &result); + opCtx, dbname, filterCommandRequestForPassthrough(cmdObj), &result); } } cmdRolesInfo; @@ -809,7 +809,7 @@ public: string& errmsg, BSONObjBuilder& result) { return Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result); + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result); } } cmdMergeAuthzCollections; @@ -899,7 +899,7 @@ public: BSONObjBuilder& result) { // Run the authSchemaUpgrade command on the config servers if (!Grid::get(opCtx)->catalogClient(opCtx)->runUserManagementWriteCommand( - opCtx, getName(), dbname, cmdObj, &result)) { + opCtx, getName(), dbname, filterCommandRequestForPassthrough(cmdObj), &result)) { return false; } diff --git a/src/mongo/s/commands/commands_public.cpp b/src/mongo/s/commands/commands_public.cpp index 16560f6b0b6..f5493186bac 100644 --- a/src/mongo/s/commands/commands_public.cpp +++ b/src/mongo/s/commands/commands_public.cpp @@ -95,7 +95,9 @@ bool cursorCommandPassthrough(OperationContext* opCtx, } const auto shard = shardStatus.getValue(); ScopedDbConnection conn(shard->getConnString()); - auto cursor = conn->query(str::stream() << dbName << ".$cmd", cmdObj, /* nToReturn=*/-1); + auto cursor = conn->query(str::stream() << dbName << ".$cmd", + Command::filterCommandRequestForPassthrough(cmdObj), + /* nToReturn=*/-1); if (!cursor || !cursor->more()) { return Command::appendCommandStatus( *out, {ErrorCodes::OperationFailed, "failed to read command response from shard"}); @@ -176,7 +178,7 @@ protected: ShardConnection conn(shard->getConnString(), ""); BSONObj res; - bool ok = conn->runCommand(db, cmdObj, res); + bool ok = conn->runCommand(db, filterCommandRequestForPassthrough(cmdObj), res); conn.done(); // First append the properly constructed writeConcernError. It will then be skipped @@ -225,7 +227,7 @@ protected: auto shardResponses = uassertStatusOK(scatterGatherForNamespace(opCtx, nss, - cmdObj, + filterCommandRequestForPassthrough(cmdObj), ReadPreferenceSetting::get(opCtx), boost::none, // filter boost::none, // collation @@ -368,8 +370,13 @@ public: vector<Strategy::CommandResult> results; const BSONObj query; - Strategy::commandOp( - opCtx, dbName, cmdObj, cm->getns(), query, CollationSpec::kSimpleSpec, &results); + Strategy::commandOp(opCtx, + dbName, + filterCommandRequestForPassthrough(cmdObj), + cm->getns(), + query, + CollationSpec::kSimpleSpec, + &results); BSONObjBuilder rawResBuilder(output.subobjStart("raw")); bool isValid = true; @@ -552,7 +559,7 @@ public: !fromDbInfo.shardingEnabled()); BSONObjBuilder b; - BSONForEach(e, cmdObj) { + BSONForEach(e, filterCommandRequestForPassthrough(cmdObj)) { if (strcmp(e.fieldName(), "fromhost") != 0) { b.append(e); } @@ -626,7 +633,7 @@ public: BSONObj res; { ScopedDbConnection conn(shard->getConnString()); - if (!conn->runCommand(dbName, cmdObj, res)) { + if (!conn->runCommand(dbName, filterCommandRequestForPassthrough(cmdObj), res)) { if (!res["code"].eoo()) { result.append(res["code"]); } @@ -814,7 +821,7 @@ public: ScopedDbConnection conn(shardStatus.getValue()->getConnString()); BSONObj res; - bool ok = conn->runCommand(dbName, cmdObj, res); + bool ok = conn->runCommand(dbName, filterCommandRequestForPassthrough(cmdObj), res); conn.done(); if (!ok) { @@ -1085,7 +1092,8 @@ public: ShardConnection conn(shardStatus.getValue()->getConnString(), nss.ns()); BSONObj res; - bool ok = conn->runCommand(nss.db().toString(), cmdObj, res); + bool ok = conn->runCommand( + nss.db().toString(), filterCommandRequestForPassthrough(cmdObj), res); conn.done(); if (!ok) { @@ -1259,8 +1267,13 @@ public: BSONObj finder = BSON("files_id" << cmdObj.firstElement()); vector<Strategy::CommandResult> results; - Strategy::commandOp( - opCtx, dbName, cmdObj, nss.ns(), finder, CollationSpec::kSimpleSpec, &results); + Strategy::commandOp(opCtx, + dbName, + filterCommandRequestForPassthrough(cmdObj), + nss.ns(), + finder, + CollationSpec::kSimpleSpec, + &results); verify(results.size() == 1); // querying on shard key so should only talk to one shard BSONObj res = results.begin()->result; @@ -1281,7 +1294,7 @@ public: // look for chunk n and it doesn't exist. This means that the file's last // chunk is n-1, so we return the computed md5 results. BSONObjBuilder bb; - bb.appendElements(cmdObj); + bb.appendElements(filterCommandRequestForPassthrough(cmdObj)); bb.appendBool("partialOk", true); bb.append("startAt", n); if (!lastResult.isEmpty()) { @@ -1415,7 +1428,7 @@ public: vector<AsyncRequestsSender::Request> requests; BSONArrayBuilder shardArray; for (const ShardId& shardId : shardIds) { - requests.emplace_back(shardId, cmdObj); + requests.emplace_back(shardId, filterCommandRequestForPassthrough(cmdObj)); shardArray.append(shardId.toString()); } diff --git a/src/mongo/s/commands/strategy.cpp b/src/mongo/s/commands/strategy.cpp index c1ca83c0234..27d621d495b 100644 --- a/src/mongo/s/commands/strategy.cpp +++ b/src/mongo/s/commands/strategy.cpp @@ -143,38 +143,6 @@ void appendRequiredFieldsToResponse(OperationContext* opCtx, BSONObjBuilder* res } } -/** - * Rewrites cmdObj into the format expected by mongos Command::run() implementations. - * - * This performs 2 transformations: - * 1) $readPreference fields are moved into a subobject called $queryOptions. This matches the - * "wrapped" format historically used internally by mongos. Moving off of that format will be - * done as SERVER-29091. - * - * 2) Filter out generic arguments that shouldn't be blindly passed to the shards. This is - * necessary because many mongos implementations of Command::run() just pass cmdObj through - * directly to the shards. However, some of the generic arguments fields are automatically - * appended in the egress layer. Removing them here ensures that they don't get duplicated. - * - * Ideally this function can be deleted once mongos run() implementations are more careful about - * what they send to the shards. - */ -BSONObj filterCommandRequestForPassthrough(const BSONObj& cmdObj) { - BSONObjBuilder bob; - for (auto elem : cmdObj) { - const auto name = elem.fieldNameStringData(); - if (name == "$readPreference") { - BSONObjBuilder(bob.subobjStart("$queryOptions")).append(elem); - } else if (!Command::isGenericArgument(name) || name == "maxTimeMS" || - name == "readConcern" || name == "writeConcern") { - // This is the whitelist of generic arguments that commands can be trusted to blindly - // forward to the shards. - bob.append(elem); - } - } - return bob.obj(); -} - void execCommandClient(OperationContext* opCtx, Command* c, StringData dbname, @@ -249,19 +217,18 @@ void execCommandClient(OperationContext* opCtx, return; } - auto filteredCmdObj = filterCommandRequestForPassthrough(cmdObj); std::string errmsg; bool ok = false; try { if (!supportsWriteConcern) { - ok = c->run(opCtx, dbname.toString(), filteredCmdObj, errmsg, result); + ok = c->run(opCtx, dbname.toString(), cmdObj, errmsg, result); } else { // Change the write concern while running the command. const auto oldWC = opCtx->getWriteConcern(); ON_BLOCK_EXIT([&] { opCtx->setWriteConcern(oldWC); }); opCtx->setWriteConcern(wcResult.getValue()); - ok = c->run(opCtx, dbname.toString(), filteredCmdObj, errmsg, result); + ok = c->run(opCtx, dbname.toString(), cmdObj, errmsg, result); } } catch (const DBException& e) { result.resetToEmpty(); diff --git a/src/mongo/s/query/cluster_find.cpp b/src/mongo/s/query/cluster_find.cpp index c282fee7800..0f7630d5dc8 100644 --- a/src/mongo/s/query/cluster_find.cpp +++ b/src/mongo/s/query/cluster_find.cpp @@ -463,20 +463,4 @@ StatusWith<CursorResponse> ClusterFind::runGetMore(OperationContext* opCtx, return CursorResponse(request.nss, idToReturn, std::move(batch), startingFrom); } -StatusWith<ReadPreferenceSetting> ClusterFind::extractUnwrappedReadPref(const BSONObj& cmdObj) { - BSONElement queryOptionsElt; - auto status = bsonExtractTypedField( - cmdObj, QueryRequest::kUnwrappedReadPrefField, BSONType::Object, &queryOptionsElt); - if (status.isOK()) { - // There must be a nested object containing the read preference if there is a queryOptions - // field. - return ReadPreferenceSetting::fromContainingBSON(queryOptionsElt.Obj()); - } else if (status != ErrorCodes::NoSuchKey) { - return status; - } - - // If there is no explicit read preference, that means primary only. - return ReadPreferenceSetting(mongo::ReadPreference::PrimaryOnly); -} - } // namespace mongo diff --git a/src/mongo/s/query/cluster_find.h b/src/mongo/s/query/cluster_find.h index 492c0dc81e2..94ad5bfb14a 100644 --- a/src/mongo/s/query/cluster_find.h +++ b/src/mongo/s/query/cluster_find.h @@ -73,17 +73,6 @@ public: */ static StatusWith<CursorResponse> runGetMore(OperationContext* opCtx, const GetMoreRequest& request); - - /** - * Extracts the read preference from 'cmdObj. - * - * Expects a read preference that has already been "unwrapped" by the mongos command handling - * code, e.g. { ... , $queryOptions: { $readPreference: { ... } } , ... }. - * - * Returns a non-OK status if 'cmdObj' has a read preference but the read preference does not - * parse correctly. - */ - static StatusWith<ReadPreferenceSetting> extractUnwrappedReadPref(const BSONObj& cmdObj); }; } // namespace mongo |