summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mongo/db/commands.cpp19
-rw-r--r--src/mongo/db/commands.h20
-rw-r--r--src/mongo/s/commands/cluster_aggregate.cpp1
-rw-r--r--src/mongo/s/commands/cluster_current_op.cpp7
-rw-r--r--src/mongo/s/commands/cluster_db_stats_cmd.cpp7
-rw-r--r--src/mongo/s/commands/cluster_explain.cpp5
-rw-r--r--src/mongo/s/commands/cluster_find_and_modify_cmd.cpp3
-rw-r--r--src/mongo/s/commands/cluster_find_cmd.cpp9
-rw-r--r--src/mongo/s/commands/cluster_get_last_error_cmd.cpp3
-rw-r--r--src/mongo/s/commands/cluster_index_filter_cmd.cpp9
-rw-r--r--src/mongo/s/commands/cluster_list_databases_cmd.cpp11
-rw-r--r--src/mongo/s/commands/cluster_map_reduce_cmd.cpp2
-rw-r--r--src/mongo/s/commands/cluster_plan_cache_cmd.cpp9
-rw-r--r--src/mongo/s/commands/cluster_reset_error_cmd.cpp2
-rw-r--r--src/mongo/s/commands/cluster_user_management_commands.cpp36
-rw-r--r--src/mongo/s/commands/commands_public.cpp39
-rw-r--r--src/mongo/s/commands/strategy.cpp37
-rw-r--r--src/mongo/s/query/cluster_find.cpp16
-rw-r--r--src/mongo/s/query/cluster_find.h11
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