diff options
-rw-r--r-- | jstests/auth/lib/commands_lib.js | 15 | ||||
-rw-r--r-- | jstests/core/views/views_all_commands.js | 1 | ||||
-rw-r--r-- | jstests/noPassthrough/cluster_commands_require_cluster_node.js | 1 | ||||
-rw-r--r-- | jstests/replsets/db_reads_while_recovering_all_commands.js | 1 | ||||
-rw-r--r-- | jstests/sharding/libs/last_lts_mongod_commands.js | 1 | ||||
-rw-r--r-- | jstests/sharding/read_write_concern_defaults_application.js | 1 | ||||
-rw-r--r-- | jstests/sharding/safe_secondary_reads_drop_recreate.js | 1 | ||||
-rw-r--r-- | jstests/sharding/safe_secondary_reads_single_migration_suspend_range_deletion.js | 1 | ||||
-rw-r--r-- | jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js | 1 | ||||
-rw-r--r-- | src/mongo/db/s/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/db/s/cluster_count_cmd_d.cpp | 66 | ||||
-rw-r--r-- | src/mongo/s/commands/SConscript | 2 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_count_cmd.h (renamed from src/mongo/s/commands/cluster_count_cmd.cpp) | 28 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_count_cmd_s.cpp | 58 |
14 files changed, 167 insertions, 12 deletions
diff --git a/jstests/auth/lib/commands_lib.js b/jstests/auth/lib/commands_lib.js index 8e7fe629ea1..1bb03846890 100644 --- a/jstests/auth/lib/commands_lib.js +++ b/jstests/auth/lib/commands_lib.js @@ -3076,6 +3076,21 @@ var authCommandsLib = { ] }, { + testname: "clusterCount", + command: {clusterCount: "x"}, + skipSharded: true, + testcases: [ + { + runOnDb: firstDbName, + roles: {__system: 1}, + privileges: [{resource: {cluster: true}, actions: ["internal"]}, {resource: {db: firstDbName, collection: "x"}, actions: ["find"]}], + // clusterCount is only supported on a shardsvr mongod so this test case is expected + // to fail when it runs against a standalone mongod. + expectFail: true, + }, + ] + }, + { testname: "count", command: {count: "x"}, testcases: [ diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js index 9c7e7500670..ea9780cf617 100644 --- a/jstests/core/views/views_all_commands.js +++ b/jstests/core/views/views_all_commands.js @@ -248,6 +248,7 @@ let viewsCommandTests = { clusterAbortTransaction: {skip: "already tested by 'abortTransaction' tests on mongos"}, clusterAggregate: {skip: "already tested by 'aggregate' tests on mongos"}, clusterCommitTransaction: {skip: "already tested by 'commitTransaction' tests on mongos"}, + clusterCount: {skip: "already tested by 'count' tests on mongos"}, clusterDelete: {skip: "already tested by 'delete' tests on mongos"}, clusterFind: {skip: "already tested by 'find' tests on mongos"}, clusterGetMore: {skip: "already tested by 'getMore' tests on mongos"}, diff --git a/jstests/noPassthrough/cluster_commands_require_cluster_node.js b/jstests/noPassthrough/cluster_commands_require_cluster_node.js index 05a4e80685f..1de23a4a6fb 100644 --- a/jstests/noPassthrough/cluster_commands_require_cluster_node.js +++ b/jstests/noPassthrough/cluster_commands_require_cluster_node.js @@ -18,6 +18,7 @@ const clusterCommandsCases = [ {cmd: {clusterAbortTransaction: 1}, expectedErr: ErrorCodes.InvalidOptions}, {cmd: {clusterAggregate: kCollName, pipeline: [{$match: {}}], cursor: {}}}, {cmd: {clusterCommitTransaction: 1}, expectedErr: ErrorCodes.InvalidOptions}, + {cmd: {clusterCount: "x"}}, {cmd: {clusterDelete: kCollName, deletes: [{q: {}, limit: 1}]}}, {cmd: {clusterFind: kCollName}}, { diff --git a/jstests/replsets/db_reads_while_recovering_all_commands.js b/jstests/replsets/db_reads_while_recovering_all_commands.js index b8179f145a1..23a4ed00c24 100644 --- a/jstests/replsets/db_reads_while_recovering_all_commands.js +++ b/jstests/replsets/db_reads_while_recovering_all_commands.js @@ -145,6 +145,7 @@ const allCommands = { clusterAbortTransaction: {skip: "already tested by 'abortTransaction' tests on mongos"}, clusterAggregate: {skip: "already tested by 'aggregate' tests on mongos"}, clusterCommitTransaction: {skip: "already tested by 'commitTransaction' tests on mongos"}, + clusterCount: {skip: "already tested by 'count' tests on mongos"}, clusterDelete: {skip: "already tested by 'delete' tests on mongos"}, clusterFind: {skip: "already tested by 'find' tests on mongos"}, clusterGetMore: {skip: "already tested by 'getMore' tests on mongos"}, diff --git a/jstests/sharding/libs/last_lts_mongod_commands.js b/jstests/sharding/libs/last_lts_mongod_commands.js index ec19e8b8342..39401bfb0a9 100644 --- a/jstests/sharding/libs/last_lts_mongod_commands.js +++ b/jstests/sharding/libs/last_lts_mongod_commands.js @@ -18,6 +18,7 @@ const commandsAddedToMongodSinceLastLTS = [ "clusterAbortTransaction", "clusterAggregate", "clusterCommitTransaction", + "clusterCount", "clusterDelete", "clusterFind", "clusterGetMore", diff --git a/jstests/sharding/read_write_concern_defaults_application.js b/jstests/sharding/read_write_concern_defaults_application.js index 84cc4791746..222e5073e69 100644 --- a/jstests/sharding/read_write_concern_defaults_application.js +++ b/jstests/sharding/read_write_concern_defaults_application.js @@ -248,6 +248,7 @@ let testCases = { clusterAbortTransaction: {skip: "already tested by 'abortTransaction' tests on mongos"}, clusterAggregate: {skip: "already tested by 'aggregate' tests on mongos"}, clusterCommitTransaction: {skip: "already tested by 'commitTransaction' tests on mongos"}, + clusterCount: {skip: "already tested by 'count' tests on mongos"}, clusterDelete: {skip: "already tested by 'delete' tests on mongos"}, clusterFind: {skip: "already tested by 'find' tests on mongos"}, clusterGetMore: {skip: "already tested by 'getMore' tests on mongos"}, diff --git a/jstests/sharding/safe_secondary_reads_drop_recreate.js b/jstests/sharding/safe_secondary_reads_drop_recreate.js index 76ae8d5155b..c4d7660486e 100644 --- a/jstests/sharding/safe_secondary_reads_drop_recreate.js +++ b/jstests/sharding/safe_secondary_reads_drop_recreate.js @@ -118,6 +118,7 @@ let testCases = { clusterAbortTransaction: {skip: "already tested by 'abortTransaction' tests on mongos"}, clusterAggregate: {skip: "already tested by 'aggregate' tests on mongos"}, clusterCommitTransaction: {skip: "already tested by 'commitTransaction' tests on mongos"}, + clusterCount: {skip: "already tested by 'count' tests on mongos"}, clusterDelete: {skip: "already tested by 'delete' tests on mongos"}, clusterFind: {skip: "already tested by 'find' tests on mongos"}, clusterGetMore: {skip: "already tested by 'getMore' tests on mongos"}, 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 82bfc3fca45..684853afdbf 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 @@ -134,6 +134,7 @@ let testCases = { clusterAbortTransaction: {skip: "already tested by 'abortTransaction' tests on mongos"}, clusterAggregate: {skip: "already tested by 'aggregate' tests on mongos"}, clusterCommitTransaction: {skip: "already tested by 'commitTransaction' tests on mongos"}, + clusterCount: {skip: "already tested by 'count' tests on mongos"}, clusterDelete: {skip: "already tested by 'delete' tests on mongos"}, clusterFind: {skip: "already tested by 'find' tests on mongos"}, clusterGetMore: {skip: "already tested by 'getMore' tests on mongos"}, diff --git a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js index ff98d2ad1a2..7a7a98a4331 100644 --- a/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js +++ b/jstests/sharding/safe_secondary_reads_single_migration_waitForDelete.js @@ -121,6 +121,7 @@ let testCases = { clusterAbortTransaction: {skip: "already tested by 'abortTransaction' tests on mongos"}, clusterAggregate: {skip: "already tested by 'aggregate' tests on mongos"}, clusterCommitTransaction: {skip: "already tested by 'commitTransaction' tests on mongos"}, + clusterCount: {skip: "already tested by 'count' tests on mongos"}, clusterDelete: {skip: "already tested by 'delete' tests on mongos"}, clusterFind: {skip: "already tested by 'find' tests on mongos"}, clusterGetMore: {skip: "already tested by 'getMore' tests on mongos"}, diff --git a/src/mongo/db/s/SConscript b/src/mongo/db/s/SConscript index a437bc2579c..da2bc3faf03 100644 --- a/src/mongo/db/s/SConscript +++ b/src/mongo/db/s/SConscript @@ -360,6 +360,7 @@ env.Library( 'clone_catalog_data_command.cpp', 'cluster_abort_transaction_cmd_d.cpp', 'cluster_commit_transaction_cmd_d.cpp', + 'cluster_count_cmd_d.cpp', 'cluster_find_cmd_d.cpp', 'cluster_getmore_cmd_d.cpp', 'cluster_pipeline_cmd_d.cpp', @@ -517,6 +518,7 @@ env.Library( '$BUILD_DIR/mongo/s/commands/sharded_cluster_sharding_commands', '$BUILD_DIR/mongo/s/sharding_initialization', '$BUILD_DIR/mongo/s/sharding_router_api', + '$BUILD_DIR/mongo/s/startup_initialization', 'forwardable_operation_metadata', 'sharding_logging', 'sharding_runtime_d', diff --git a/src/mongo/db/s/cluster_count_cmd_d.cpp b/src/mongo/db/s/cluster_count_cmd_d.cpp new file mode 100644 index 00000000000..e291ec2ee29 --- /dev/null +++ b/src/mongo/db/s/cluster_count_cmd_d.cpp @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2022-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/s/sharding_state.h" +#include "mongo/s/commands/cluster_count_cmd.h" +#include "mongo/s/grid.h" + +namespace mongo { +namespace { + +/** + * Implements the cluster count command on mongod. + */ +struct ClusterCountCmdD { + static constexpr StringData kName = "clusterCount"_sd; + + static const std::set<std::string>& getApiVersions() { + return kNoApiVersions; + } + + static void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) { + ActionSet actions; + actions.addAction(ActionType::internal); + out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + } + + static void checkCanRunHere(OperationContext* opCtx) { + Grid::get(opCtx)->assertShardingIsInitialized(); + + // A cluster command on the config server may attempt to use a ShardLocal to target itself, + // which triggers an invariant, so only shard servers can run this. + uassertStatusOK(ShardingState::get(opCtx)->canAcceptShardedCommands()); + } +}; +ClusterCountCmdBase<ClusterCountCmdD> clusterCountCmdD; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript index 7dd1f0bc554..05d44aea84f 100644 --- a/src/mongo/s/commands/SConscript +++ b/src/mongo/s/commands/SConscript @@ -37,7 +37,7 @@ env.Library( 'cluster_compact_cmd.cpp', 'cluster_convert_to_capped_cmd.cpp', 'cluster_coordinate_commit_txn.cpp', - 'cluster_count_cmd.cpp', + 'cluster_count_cmd_s.cpp', 'cluster_create_cmd.cpp', 'cluster_create_indexes_cmd.cpp', 'cluster_current_op.cpp', diff --git a/src/mongo/s/commands/cluster_count_cmd.cpp b/src/mongo/s/commands/cluster_count_cmd.h index c1603f8813e..9b913ac2afa 100644 --- a/src/mongo/s/commands/cluster_count_cmd.cpp +++ b/src/mongo/s/commands/cluster_count_cmd.h @@ -1,5 +1,5 @@ /** - * Copyright (C) 2018-present MongoDB, Inc. + * Copyright (C) 2022-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, @@ -27,7 +27,7 @@ * it in the license file. */ -#include "mongo/platform/basic.h" +#pragma once #include <vector> @@ -48,14 +48,17 @@ #include "mongo/util/timer.h" namespace mongo { -namespace { -class ClusterCountCmd : public ErrmsgCommandDeprecated { +/** + * Implements the find command on mongos. + */ +template <typename Impl> +class ClusterCountCmdBase final : public ErrmsgCommandDeprecated { public: - ClusterCountCmd() : ErrmsgCommandDeprecated("count") {} + ClusterCountCmdBase() : ErrmsgCommandDeprecated(Impl::kName) {} const std::set<std::string>& apiVersions() const { - return kApiVersions1; + return Impl::getApiVersions(); } AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { @@ -85,6 +88,7 @@ public: ActionSet actions; actions.addAction(ActionType::find); out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + Impl::addRequiredPrivileges(dbname, cmdObj, out); } bool errmsgRun(OperationContext* opCtx, @@ -92,6 +96,8 @@ public: const BSONObj& cmdObj, std::string& errmsg, BSONObjBuilder& result) override { + Impl::checkCanRunHere(opCtx); + CommandHelpers::handleMarkKillOnClientDisconnect(opCtx); const NamespaceString nss(parseNs({boost::none, dbname}, cmdObj)); uassert(ErrorCodes::InvalidNamespace, @@ -195,6 +201,8 @@ public: const OpMsgRequest& request, ExplainOptions::Verbosity verbosity, rpc::ReplyBuilderInterface* result) const override { + Impl::checkCanRunHere(opCtx); + const BSONObj& cmdObj = request.body; CountCommandRequest countRequest(NamespaceStringOrUUID(NamespaceString{})); @@ -259,8 +267,8 @@ public: APIParameters::get(opCtx).getAPIStrict().value_or(false)); auto bodyBuilder = result->getBodyBuilder(); - // An empty PrivilegeVector is acceptable because these privileges are only checked on - // getMore and explain will not open a cursor. + // An empty PrivilegeVector is acceptable because these privileges are only checked + // on getMore and explain will not open a cursor. return ClusterAggregate::retryOnViewError(opCtx, aggRequestOnView, *ex.extraInfo<ResolvedView>(), @@ -305,8 +313,6 @@ private: return num; } +}; -} clusterCountCmd; - -} // namespace } // namespace mongo diff --git a/src/mongo/s/commands/cluster_count_cmd_s.cpp b/src/mongo/s/commands/cluster_count_cmd_s.cpp new file mode 100644 index 00000000000..d177d19d5ec --- /dev/null +++ b/src/mongo/s/commands/cluster_count_cmd_s.cpp @@ -0,0 +1,58 @@ +/** + * Copyright (C) 2022-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/s/commands/cluster_count_cmd.h" + +namespace mongo { +namespace { + +/** + * Implements the cluster count command on mongos. + */ +struct ClusterCountCmdS { + static constexpr StringData kName = "count"_sd; + + static const std::set<std::string>& getApiVersions() { + return kApiVersions1; + } + + static void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) { + // No additional required privileges on a mongos. + } + + static void checkCanRunHere(OperationContext* opCtx) { + // Can always run on a mongos. + } +}; +ClusterCountCmdBase<ClusterCountCmdS> clusterCountCmdS; + +} // namespace +} // namespace mongo |