diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2020-06-05 07:58:16 -0400 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2020-06-08 07:38:58 +0000 |
commit | 43becb34df823529e205e41137e503feb9f3ee63 (patch) | |
tree | 14bc783762dad78cb1ea20fdc729117f0ba0abda /src/mongo/s | |
parent | 3a08edc2ed39f7747fa034b449caa569dba72ace (diff) | |
download | mongo-43becb34df823529e205e41137e503feb9f3ee63.tar.gz |
SERVER-47979 Perform the collation check for `shardCollection` on the shard
.... rather than doing it on the config server, because the stability of
the collection cannot be guaranteed.
Diffstat (limited to 'src/mongo/s')
-rw-r--r-- | src/mongo/s/commands/SConscript | 11 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_commands.idl (renamed from src/mongo/s/commands/kill_sessions_remote.idl) | 56 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_list_collections_cmd.cpp | 227 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_list_indexes_cmd.cpp | 135 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_multicast.idl | 50 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_multicast_cmd.cpp (renamed from src/mongo/s/commands/cluster_multicast.cpp) | 45 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_passthrough_commands.cpp | 274 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_set_free_monitoring_cmd.cpp (renamed from src/mongo/s/commands/cluster_set_free_monitoring.cpp) | 0 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_shard_collection_cmd.cpp | 17 | ||||
-rw-r--r-- | src/mongo/s/commands/commands_public.cpp | 569 | ||||
-rw-r--r-- | src/mongo/s/commands/kill_sessions_remote.cpp | 8 | ||||
-rw-r--r-- | src/mongo/s/commands/kill_sessions_remote.h | 5 | ||||
-rw-r--r-- | src/mongo/s/request_types/shard_collection.idl | 46 |
13 files changed, 722 insertions, 721 deletions
diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript index 9f7c310ffef..3db993ea17e 100644 --- a/src/mongo/s/commands/SConscript +++ b/src/mongo/s/commands/SConscript @@ -62,15 +62,18 @@ env.Library( 'cluster_kill_op.cpp', 'cluster_killcursors_cmd.cpp', 'cluster_killoperations_cmd.cpp', + 'cluster_list_collections_cmd.cpp', 'cluster_list_databases_cmd.cpp', + 'cluster_list_indexes_cmd.cpp', 'cluster_list_shards_cmd.cpp', 'cluster_map_reduce_agg.cpp', 'cluster_map_reduce_cmd.cpp', 'cluster_merge_chunks_cmd.cpp', 'cluster_move_chunk_cmd.cpp', 'cluster_move_primary_cmd.cpp', - 'cluster_multicast.cpp', + 'cluster_multicast_cmd.cpp', 'cluster_netstat_cmd.cpp', + 'cluster_passthrough_commands.cpp', 'cluster_pipeline_cmd.cpp', 'cluster_plan_cache_clear_cmd.cpp', 'cluster_profile_cmd.cpp', @@ -81,7 +84,7 @@ env.Library( 'cluster_reset_error_cmd.cpp', 'cluster_rwc_defaults_commands.cpp', 'cluster_set_feature_compatibility_version_cmd.cpp', - 'cluster_set_free_monitoring.cpp' if get_option("enable-free-mon") == 'on' else [], + 'cluster_set_free_monitoring_cmd.cpp' if get_option("enable-free-mon") == 'on' else [], 'cluster_set_index_commit_quorum_cmd.cpp', 'cluster_shard_collection_cmd.cpp', 'cluster_shutdown_cmd.cpp', @@ -91,13 +94,11 @@ env.Library( 'cluster_validate_cmd.cpp', 'cluster_whats_my_uri_cmd.cpp', 'cluster_write_cmd.cpp', - 'commands_public.cpp', 'document_shard_key_update_util.cpp', 'kill_sessions_remote.cpp', 's_read_write_concern_defaults_server_status.cpp', 'strategy.cpp', - env.Idlc('cluster_multicast.idl')[0], - env.Idlc('kill_sessions_remote.idl')[0], + env.Idlc('cluster_commands.idl')[0], ], LIBDEPS=[ '$BUILD_DIR/mongo/db/commands/servers', diff --git a/src/mongo/s/commands/kill_sessions_remote.idl b/src/mongo/s/commands/cluster_commands.idl index e48f99f7162..3f95b7f0181 100644 --- a/src/mongo/s/commands/kill_sessions_remote.idl +++ b/src/mongo/s/commands/cluster_commands.idl @@ -1,4 +1,4 @@ -# Copyright (C) 2019-present MongoDB, Inc. +# Copyright (C) 2018-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, @@ -24,9 +24,13 @@ # 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. +# global: - cpp_namespace: mongo + cpp_namespace: "mongo" + +imports: + - "mongo/idl/basic_types.idl" server_parameters: KillSessionsMaxConcurrency: @@ -44,3 +48,51 @@ server_parameters: cpp_vartype: int cpp_varname: gKillSessionsPerHostTimeoutMS default: 60000 + +structs: + ClusterMulticast: + description: "A struct representing the 'multicast' command's arguments" + strict: false + fields: + multicast: object + $db: + type: string + cpp_name: db + concurrency: + type: int + optional: true + timeout: + type: int + optional: true + + ShardCollection: + description: "The public shardCollection command on mongos" + strict: false + fields: + shardCollection: + type: namespacestring + description: "The namespace of the collection to shard in the form <database>.<collection>." + optional: true + shardcollection: + type: namespacestring + description: "Same as the previous field, but refers to the deprecated version of this command's name" + optional: true + key: + type: object + description: "The index specification document to use as the shard key." + unique: + type: bool + description: "Whether the shard key index should enforce a unique constraint" + default: false + numInitialChunks: + type: safeInt64 + description: "The number of chunks to create initially when sharding an empty collection with a hashed shard key." + default: 0 + presplitHashedZones: + type: bool + description: "True if the chunks should be pre-split based on the existing zones when sharding a collection with hashed shard key" + default: false + collation: + type: object + description: "The collation to use for the shard key index." + optional: true diff --git a/src/mongo/s/commands/cluster_list_collections_cmd.cpp b/src/mongo/s/commands/cluster_list_collections_cmd.cpp new file mode 100644 index 00000000000..255d4ec7453 --- /dev/null +++ b/src/mongo/s/commands/cluster_list_collections_cmd.cpp @@ -0,0 +1,227 @@ +/** + * 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. + */ + +#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand + +#include "mongo/platform/basic.h" + +#include "mongo/bson/mutable/algorithm.h" +#include "mongo/bson/mutable/document.h" +#include "mongo/db/auth/authorization_session.h" +#include "mongo/db/commands.h" +#include "mongo/s/cluster_commands_helpers.h" +#include "mongo/s/query/store_possible_cursor.h" + +namespace mongo { +namespace { + +bool cursorCommandPassthroughPrimaryShard(OperationContext* opCtx, + StringData dbName, + const CachedDatabaseInfo& dbInfo, + const BSONObj& cmdObj, + const NamespaceString& nss, + BSONObjBuilder* out, + const PrivilegeVector& privileges) { + auto response = executeCommandAgainstDatabasePrimary( + opCtx, + dbName, + dbInfo, + CommandHelpers::filterCommandRequestForPassthrough(cmdObj), + ReadPreferenceSetting::get(opCtx), + Shard::RetryPolicy::kIdempotent); + const auto cmdResponse = uassertStatusOK(std::move(response.swResponse)); + + auto transformedResponse = uassertStatusOK( + storePossibleCursor(opCtx, + dbInfo.primaryId(), + *response.shardHostAndPort, + cmdResponse.data, + nss, + Grid::get(opCtx)->getExecutorPool()->getArbitraryExecutor(), + Grid::get(opCtx)->getCursorManager(), + privileges)); + + CommandHelpers::filterCommandReplyForPassthrough(transformedResponse, out); + return true; +} + +BSONObj rewriteCommandForListingOwnCollections(OperationContext* opCtx, + const std::string& dbName, + const BSONObj& cmdObj) { + mutablebson::Document rewrittenCmdObj(cmdObj); + mutablebson::Element ownCollections = + mutablebson::findFirstChildNamed(rewrittenCmdObj.root(), "authorizedCollections"); + + AuthorizationSession* authzSession = AuthorizationSession::get(opCtx->getClient()); + + // We must strip $ownCollections from the delegated command. + uassertStatusOK(ownCollections.remove()); + + BSONObj collectionFilter; + + // Extract and retain any previous filter + mutablebson::Element oldFilter = + mutablebson::findFirstChildNamed(rewrittenCmdObj.root(), "filter"); + + // Make a new filter, containing a $and array. + mutablebson::Element newFilter = rewrittenCmdObj.makeElementObject("filter"); + mutablebson::Element newFilterAnd = rewrittenCmdObj.makeElementArray("$and"); + uassertStatusOK(newFilter.pushBack(newFilterAnd)); + + mutablebson::Element newFilterOr = rewrittenCmdObj.makeElementArray("$or"); + mutablebson::Element newFilterOrObj = rewrittenCmdObj.makeElementObject(""); + uassertStatusOK(newFilterOrObj.pushBack(newFilterOr)); + uassertStatusOK(newFilterAnd.pushBack(newFilterOrObj)); + + // DB resource grants all non-system collections, so filter out system collections. This is done + // inside the $or, since some system collections might be granted specific privileges. + if (authzSession->isAuthorizedForAnyActionOnResource( + ResourcePattern::forDatabaseName(dbName))) { + mutablebson::Element systemCollectionsFilter = rewrittenCmdObj.makeElementObject( + "", BSON("name" << BSON("$regex" << BSONRegEx("^(?!system\\.)")))); + uassertStatusOK(newFilterOr.pushBack(systemCollectionsFilter)); + } + + // Compute the set of collection names which would be permissible to return. + std::set<std::string> collectionNames; + for (UserNameIterator nameIter = authzSession->getAuthenticatedUserNames(); nameIter.more(); + nameIter.next()) { + User* authUser = authzSession->lookupUser(*nameIter); + const User::ResourcePrivilegeMap& resourcePrivilegeMap = authUser->getPrivileges(); + for (const std::pair<ResourcePattern, Privilege>& resourcePrivilege : + resourcePrivilegeMap) { + const auto& resource = resourcePrivilege.first; + if (resource.isCollectionPattern() || + (resource.isExactNamespacePattern() && resource.databaseToMatch() == dbName)) { + collectionNames.emplace(resource.collectionToMatch().toString()); + } + } + } + + // Construct a new filter predicate which returns only collections we were found to have + // privileges for. + BSONObjBuilder predicateBuilder; + BSONObjBuilder nameBuilder(predicateBuilder.subobjStart("name")); + BSONArrayBuilder setBuilder(nameBuilder.subarrayStart("$in")); + + // Load the de-duplicated set into a BSON array + for (StringData collectionName : collectionNames) { + setBuilder << collectionName; + } + setBuilder.done(); + nameBuilder.done(); + + collectionFilter = predicateBuilder.obj(); + + // Filter the results by our collection names. + mutablebson::Element newFilterCollections = + rewrittenCmdObj.makeElementObject("", collectionFilter); + uassertStatusOK(newFilterOr.pushBack(newFilterCollections)); + + // If there was a pre-existing filter, compose it with our new one. + if (oldFilter.ok()) { + uassertStatusOK(oldFilter.remove()); + uassertStatusOK(newFilterAnd.pushBack(oldFilter)); + } + + // Attach our new composite filter back onto the listCollections command object. + uassertStatusOK(rewrittenCmdObj.root().pushBack(newFilter)); + + return rewrittenCmdObj.getObject(); +} + +class CmdListCollections : public BasicCommand { +public: + CmdListCollections() : BasicCommand("listCollections") {} + + bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + + bool maintenanceOk() const override { + return false; + } + + bool adminOnly() const override { + return false; + } + + Status checkAuthForCommand(Client* client, + const std::string& dbname, + const BSONObj& cmdObj) const final { + AuthorizationSession* authzSession = AuthorizationSession::get(client); + + if (authzSession->checkAuthorizedToListCollections(dbname, cmdObj).isOK()) { + return Status::OK(); + } + + return Status(ErrorCodes::Unauthorized, + str::stream() << "Not authorized to list collections on db: " << dbname); + } + + bool run(OperationContext* opCtx, + const std::string& dbName, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { + CommandHelpers::handleMarkKillOnClientDisconnect(opCtx); + + const auto nss(NamespaceString::makeListCollectionsNSS(dbName)); + + BSONObj newCmd = cmdObj; + + AuthorizationSession* authzSession = AuthorizationSession::get(opCtx->getClient()); + if (authzSession->getAuthorizationManager().isAuthEnabled() && + newCmd["authorizedCollections"].trueValue()) { + newCmd = rewriteCommandForListingOwnCollections(opCtx, dbName, cmdObj); + } + + auto dbInfoStatus = Grid::get(opCtx)->catalogCache()->getDatabase(opCtx, dbName); + if (!dbInfoStatus.isOK()) { + return appendEmptyResultSet(opCtx, result, dbInfoStatus.getStatus(), nss.ns()); + } + + return cursorCommandPassthroughPrimaryShard( + opCtx, + dbName, + dbInfoStatus.getValue(), + applyReadWriteConcern(opCtx, this, newCmd), + nss, + &result, + uassertStatusOK(AuthorizationSession::get(opCtx->getClient()) + ->checkAuthorizedToListCollections(dbName, cmdObj))); + } + +} cmdListCollections; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_list_indexes_cmd.cpp b/src/mongo/s/commands/cluster_list_indexes_cmd.cpp new file mode 100644 index 00000000000..56828a9ee95 --- /dev/null +++ b/src/mongo/s/commands/cluster_list_indexes_cmd.cpp @@ -0,0 +1,135 @@ +/** + * 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. + */ + +#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand + +#include "mongo/platform/basic.h" + +#include "mongo/db/auth/authorization_session.h" +#include "mongo/db/commands.h" +#include "mongo/s/cluster_commands_helpers.h" +#include "mongo/s/query/store_possible_cursor.h" + +namespace mongo { +namespace { + +bool cursorCommandPassthroughShardWithMinKeyChunk(OperationContext* opCtx, + const NamespaceString& nss, + const CachedCollectionRoutingInfo& routingInfo, + const BSONObj& cmdObj, + BSONObjBuilder* out, + const PrivilegeVector& privileges) { + auto response = executeCommandAgainstShardWithMinKeyChunk( + opCtx, + nss, + routingInfo, + CommandHelpers::filterCommandRequestForPassthrough(cmdObj), + ReadPreferenceSetting::get(opCtx), + Shard::RetryPolicy::kIdempotent); + const auto cmdResponse = uassertStatusOK(std::move(response.swResponse)); + + auto transformedResponse = uassertStatusOK( + storePossibleCursor(opCtx, + response.shardId, + *response.shardHostAndPort, + cmdResponse.data, + nss, + Grid::get(opCtx)->getExecutorPool()->getArbitraryExecutor(), + Grid::get(opCtx)->getCursorManager(), + privileges)); + + CommandHelpers::filterCommandReplyForPassthrough(transformedResponse, out); + return true; +} + +class CmdListIndexes : public BasicCommand { +public: + CmdListIndexes() : BasicCommand("listIndexes") {} + + std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { + return CommandHelpers::parseNsCollectionRequired(dbname, cmdObj).ns(); + } + + bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + + bool maintenanceOk() const override { + return false; + } + + bool adminOnly() const override { + return false; + } + + Status checkAuthForCommand(Client* client, + const std::string& dbname, + const BSONObj& cmdObj) const override { + AuthorizationSession* authzSession = AuthorizationSession::get(client); + + // Check for the listIndexes ActionType on the database. + const NamespaceString ns(parseNs(dbname, cmdObj)); + + if (authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns), + ActionType::listIndexes)) { + return Status::OK(); + } + + return Status(ErrorCodes::Unauthorized, + str::stream() + << "Not authorized to list indexes on collection: " << ns.coll()); + } + + bool run(OperationContext* opCtx, + const std::string& dbName, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { + CommandHelpers::handleMarkKillOnClientDisconnect(opCtx); + + const NamespaceString nss(parseNs(dbName, cmdObj)); + const auto routingInfo = + uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); + + return cursorCommandPassthroughShardWithMinKeyChunk( + opCtx, + nss, + routingInfo, + applyReadWriteConcern(opCtx, this, cmdObj), + &result, + {Privilege(ResourcePattern::forExactNamespace(nss), ActionType::listIndexes)}); + } + +} cmdListIndexes; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_multicast.idl b/src/mongo/s/commands/cluster_multicast.idl deleted file mode 100644 index ec3afe474d4..00000000000 --- a/src/mongo/s/commands/cluster_multicast.idl +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright (C) 2018-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. -# - -global: - cpp_namespace: "mongo" - -imports: - - "mongo/idl/basic_types.idl" - -structs: - - ClusterMulticastArgs: - description: "A struct representing cluster multicast args" - strict: false - fields: - multicast: object - $db: - type: string - cpp_name: db - concurrency: - type: int - optional: true - timeout: - type: int - optional: true diff --git a/src/mongo/s/commands/cluster_multicast.cpp b/src/mongo/s/commands/cluster_multicast_cmd.cpp index 496232aa191..f74c4da2112 100644 --- a/src/mongo/s/commands/cluster_multicast.cpp +++ b/src/mongo/s/commands/cluster_multicast_cmd.cpp @@ -36,10 +36,9 @@ #include "mongo/db/commands/test_commands_enabled.h" #include "mongo/executor/async_multicaster.h" #include "mongo/executor/task_executor_pool.h" -#include "mongo/s/catalog/sharding_catalog_client.h" #include "mongo/s/catalog/type_shard.h" #include "mongo/s/client/shard_registry.h" -#include "mongo/s/commands/cluster_multicast_gen.h" +#include "mongo/s/commands/cluster_commands_gen.h" #include "mongo/s/grid.h" namespace mongo { @@ -64,18 +63,18 @@ std::vector<HostAndPort> getAllClusterHosts(OperationContext* opCtx) { return servers; } -class MulticastCmd : public BasicCommand { +class ClusterMulticastCmd : public BasicCommand { public: - MulticastCmd() : BasicCommand("multicast") {} + ClusterMulticastCmd() : BasicCommand("multicast") {} AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { return AllowedOnSecondary::kAlways; } + bool adminOnly() const override { return true; } - bool supportsWriteConcern(const BSONObj& cmd) const override { return false; } @@ -93,8 +92,8 @@ public: const std::string& dbname, const BSONObj& cmdObj, BSONObjBuilder& result) override { - IDLParserErrorContext ctx("ClusterMulticastArgs"); - auto args = ClusterMulticastArgs::parse(ctx, cmdObj); + IDLParserErrorContext ctx("ClusterMulticast"); + auto args = ClusterMulticast::parse(ctx, cmdObj); // Grab an arbitrary executor. auto executor = Grid::get(opCtx)->getExecutorPool()->getArbitraryExecutor(); @@ -118,26 +117,24 @@ public: bool success = true; - { - BSONObjBuilder bob(result.subobjStart("hosts")); + BSONObjBuilder bob(result.subobjStart("hosts")); - for (const auto& r : results) { - HostAndPort host; - executor::RemoteCommandResponse response; - std::tie(host, response) = r; + for (const auto& r : results) { + HostAndPort host; + executor::RemoteCommandResponse response; + std::tie(host, response) = r; - if (!response.isOK() || !response.data["ok"].trueValue()) { - success = false; - } + if (!response.isOK() || !response.data["ok"].trueValue()) { + success = false; + } - { - BSONObjBuilder subbob(bob.subobjStart(host.toString())); + { + BSONObjBuilder subbob(bob.subobjStart(host.toString())); - if (CommandHelpers::appendCommandStatusNoThrow(subbob, response.status)) { - subbob.append("data", response.data); - if (response.elapsedMillis) { - subbob.append("elapsedMillis", response.elapsedMillis->count()); - } + if (CommandHelpers::appendCommandStatusNoThrow(subbob, response.status)) { + subbob.append("data", response.data); + if (response.elapsedMillis) { + subbob.append("elapsedMillis", response.elapsedMillis->count()); } } } @@ -147,7 +144,7 @@ public: } }; -MONGO_REGISTER_TEST_COMMAND(MulticastCmd); +MONGO_REGISTER_TEST_COMMAND(ClusterMulticastCmd); } // namespace } // namespace mongo diff --git a/src/mongo/s/commands/cluster_passthrough_commands.cpp b/src/mongo/s/commands/cluster_passthrough_commands.cpp new file mode 100644 index 00000000000..ccb5ee5799d --- /dev/null +++ b/src/mongo/s/commands/cluster_passthrough_commands.cpp @@ -0,0 +1,274 @@ +/** + * Copyright (C) 2018-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. + */ + +#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand + +#include "mongo/platform/basic.h" + +#include "mongo/db/auth/action_set.h" +#include "mongo/db/auth/action_type.h" +#include "mongo/db/auth/authorization_session.h" +#include "mongo/db/auth/privilege.h" +#include "mongo/db/commands.h" +#include "mongo/db/commands/rename_collection_common.h" +#include "mongo/db/commands/rename_collection_gen.h" +#include "mongo/executor/task_executor_pool.h" +#include "mongo/rpc/get_status_from_command_result.h" +#include "mongo/s/cluster_commands_helpers.h" +#include "mongo/s/grid.h" + +namespace mongo { +namespace { + +bool nonShardedCollectionCommandPassthrough(OperationContext* opCtx, + StringData dbName, + const NamespaceString& nss, + const CachedCollectionRoutingInfo& routingInfo, + const BSONObj& cmdObj, + Shard::RetryPolicy retryPolicy, + BSONObjBuilder* out) { + const StringData cmdName(cmdObj.firstElementFieldName()); + uassert(ErrorCodes::IllegalOperation, + str::stream() << "Can't do command: " << cmdName << " on a sharded collection", + !routingInfo.cm()); + + auto responses = scatterGatherVersionedTargetByRoutingTable(opCtx, + dbName, + nss, + routingInfo, + cmdObj, + ReadPreferenceSetting::get(opCtx), + retryPolicy, + {}, + {}); + invariant(responses.size() == 1); + + const auto cmdResponse = uassertStatusOK(std::move(responses.front().swResponse)); + const auto status = getStatusFromCommandResult(cmdResponse.data); + + uassert(ErrorCodes::IllegalOperation, + str::stream() << "Can't do command: " << cmdName << " on a sharded collection", + !ErrorCodes::isStaleShardVersionError(status)); + + out->appendElementsUnique(CommandHelpers::filterCommandReplyForPassthrough(cmdResponse.data)); + return status.isOK(); +} + +class RenameCollectionCmd : public BasicCommand { +public: + RenameCollectionCmd() : BasicCommand("renameCollection") {} + + std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { + return CommandHelpers::parseNsFullyQualified(cmdObj); + } + + bool adminOnly() const override { + return true; + } + + bool supportsWriteConcern(const BSONObj& cmd) const override { + return true; + } + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kNever; + } + + Status checkAuthForCommand(Client* client, + const std::string& dbname, + const BSONObj& cmdObj) const override { + return rename_collection::checkAuthForRenameCollectionCommand(client, dbname, cmdObj); + } + + bool run(OperationContext* opCtx, + const std::string& dbName, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { + auto renameRequest = + RenameCollectionCommand::parse(IDLParserErrorContext("renameCollection"), cmdObj); + auto fromNss = renameRequest.getCommandParameter(); + auto toNss = renameRequest.getTo(); + + uassert(ErrorCodes::InvalidNamespace, + str::stream() << "Invalid target namespace: " << toNss.ns(), + toNss.isValid()); + + const auto fromRoutingInfo = uassertStatusOK( + Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, fromNss)); + uassert(13138, "You can't rename a sharded collection", !fromRoutingInfo.cm()); + + const auto toRoutingInfo = uassertStatusOK( + Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, toNss)); + uassert(13139, "You can't rename to a sharded collection", !toRoutingInfo.cm()); + + uassert(13137, + "Source and destination collections must be on same shard", + fromRoutingInfo.db().primaryId() == toRoutingInfo.db().primaryId()); + + return nonShardedCollectionCommandPassthrough( + opCtx, + NamespaceString::kAdminDb, + fromNss, + fromRoutingInfo, + applyReadWriteConcern( + opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)), + Shard::RetryPolicy::kNoRetry, + &result); + } + +} renameCollectionCmd; + +class ConvertToCappedCmd : public BasicCommand { +public: + ConvertToCappedCmd() : BasicCommand("convertToCapped") {} + + bool supportsWriteConcern(const BSONObj& cmd) const override { + return true; + } + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kNever; + } + + std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { + return CommandHelpers::parseNsCollectionRequired(dbname, cmdObj).ns(); + } + + void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) const override { + ActionSet actions; + actions.addAction(ActionType::convertToCapped); + out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); + } + + bool run(OperationContext* opCtx, + const std::string& dbName, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { + const NamespaceString nss(parseNs(dbName, cmdObj)); + const auto routingInfo = + uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); + uassert(ErrorCodes::IllegalOperation, + "You can't convertToCapped a sharded collection", + !routingInfo.cm()); + + // convertToCapped creates a temp collection and renames it at the end. It will require + // special handling for create collection. + return nonShardedCollectionCommandPassthrough( + opCtx, + dbName, + nss, + routingInfo, + applyReadWriteConcern( + opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)), + Shard::RetryPolicy::kIdempotent, + &result); + } + +} convertToCappedCmd; + +class SplitVectorCmd : public BasicCommand { +public: + SplitVectorCmd() : BasicCommand("splitVector") {} + + AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { + return AllowedOnSecondary::kAlways; + } + + std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { + return CommandHelpers::parseNsFullyQualified(cmdObj); + } + + bool supportsWriteConcern(const BSONObj& cmd) const override { + return false; + } + + Status checkAuthForCommand(Client* client, + const std::string& dbname, + const BSONObj& cmdObj) const override { + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), + ActionType::splitVector)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + return Status::OK(); + } + + bool run(OperationContext* opCtx, + const std::string& dbName, + const BSONObj& cmdObj, + BSONObjBuilder& result) override { + const NamespaceString nss(parseNs(dbName, cmdObj)); + uassert(ErrorCodes::IllegalOperation, + "Performing splitVector across dbs isn't supported via mongos", + nss.db() == dbName); + + const auto routingInfo = + uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); + uassert(ErrorCodes::IllegalOperation, + str::stream() << "can't do command: " << getName() << " on sharded collection", + !routingInfo.cm()); + + const auto primaryShard = routingInfo.db().primary(); + + // Here, we first filter the command before appending an UNSHARDED shardVersion, because + // "shardVersion" is one of the fields that gets filtered out. + BSONObj filteredCmdObj(applyReadWriteConcern( + opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj))); + BSONObj filteredCmdObjWithVersion( + appendShardVersion(filteredCmdObj, ChunkVersion::UNSHARDED())); + + auto commandResponse = uassertStatusOK(primaryShard->runCommandWithFixedRetryAttempts( + opCtx, + ReadPreferenceSetting::get(opCtx), + dbName, + primaryShard->isConfig() ? filteredCmdObj : filteredCmdObjWithVersion, + Shard::RetryPolicy::kIdempotent)); + + uassert(ErrorCodes::IllegalOperation, + str::stream() << "can't do command: " << getName() << " on a sharded collection", + !ErrorCodes::isStaleShardVersionError(commandResponse.commandStatus.code())); + + uassertStatusOK(commandResponse.commandStatus); + + if (!commandResponse.writeConcernStatus.isOK()) { + appendWriteConcernErrorToCmdResponse( + primaryShard->getId(), commandResponse.response["writeConcernError"], result); + } + result.appendElementsUnique( + CommandHelpers::filterCommandReplyForPassthrough(std::move(commandResponse.response))); + + return true; + } + +} splitVectorCmd; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_set_free_monitoring.cpp b/src/mongo/s/commands/cluster_set_free_monitoring_cmd.cpp index d54cd80b219..d54cd80b219 100644 --- a/src/mongo/s/commands/cluster_set_free_monitoring.cpp +++ b/src/mongo/s/commands/cluster_set_free_monitoring_cmd.cpp diff --git a/src/mongo/s/commands/cluster_shard_collection_cmd.cpp b/src/mongo/s/commands/cluster_shard_collection_cmd.cpp index c0f311de262..d27fd037d30 100644 --- a/src/mongo/s/commands/cluster_shard_collection_cmd.cpp +++ b/src/mongo/s/commands/cluster_shard_collection_cmd.cpp @@ -31,33 +31,18 @@ #include "mongo/platform/basic.h" -#include <list> -#include <set> -#include <vector> - -#include "mongo/bson/simple_bsonelement_comparator.h" -#include "mongo/bson/simple_bsonobj_comparator.h" -#include "mongo/bson/util/bson_extract.h" -#include "mongo/client/connpool.h" #include "mongo/db/audit.h" #include "mongo/db/auth/action_set.h" #include "mongo/db/auth/action_type.h" #include "mongo/db/auth/authorization_session.h" #include "mongo/db/client.h" #include "mongo/db/commands.h" -#include "mongo/db/hasher.h" -#include "mongo/db/index/index_descriptor.h" -#include "mongo/db/operation_context.h" -#include "mongo/db/query/collation/collator_factory_interface.h" -#include "mongo/db/write_concern_options.h" -#include "mongo/s/balancer_configuration.h" -#include "mongo/s/catalog/sharding_catalog_client.h" #include "mongo/s/catalog_cache.h" #include "mongo/s/client/shard_registry.h" #include "mongo/s/cluster_commands_helpers.h" +#include "mongo/s/commands/cluster_commands_gen.h" #include "mongo/s/config_server_client.h" #include "mongo/s/grid.h" -#include "mongo/s/request_types/migration_secondary_throttle_options.h" #include "mongo/s/request_types/shard_collection_gen.h" #include "mongo/util/scopeguard.h" diff --git a/src/mongo/s/commands/commands_public.cpp b/src/mongo/s/commands/commands_public.cpp deleted file mode 100644 index d943afc4e5c..00000000000 --- a/src/mongo/s/commands/commands_public.cpp +++ /dev/null @@ -1,569 +0,0 @@ -/** - * Copyright (C) 2018-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. - */ - -#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand - -#include "mongo/platform/basic.h" - -#include "mongo/bson/mutable/algorithm.h" -#include "mongo/bson/mutable/document.h" -#include "mongo/db/auth/action_set.h" -#include "mongo/db/auth/action_type.h" -#include "mongo/db/auth/authorization_session.h" -#include "mongo/db/auth/privilege.h" -#include "mongo/db/commands.h" -#include "mongo/db/commands/rename_collection.h" -#include "mongo/db/commands/rename_collection_gen.h" -#include "mongo/executor/task_executor_pool.h" -#include "mongo/rpc/get_status_from_command_result.h" -#include "mongo/s/cluster_commands_helpers.h" -#include "mongo/s/commands/cluster_explain.h" -#include "mongo/s/grid.h" -#include "mongo/s/query/store_possible_cursor.h" -#include "mongo/util/fail_point.h" -#include "mongo/util/timer.h" - -namespace mongo { - -namespace { - -bool cursorCommandPassthroughPrimaryShard(OperationContext* opCtx, - StringData dbName, - const CachedDatabaseInfo& dbInfo, - const BSONObj& cmdObj, - const NamespaceString& nss, - BSONObjBuilder* out, - const PrivilegeVector& privileges) { - auto response = executeCommandAgainstDatabasePrimary( - opCtx, - dbName, - dbInfo, - CommandHelpers::filterCommandRequestForPassthrough(cmdObj), - ReadPreferenceSetting::get(opCtx), - Shard::RetryPolicy::kIdempotent); - const auto cmdResponse = uassertStatusOK(std::move(response.swResponse)); - - auto transformedResponse = uassertStatusOK( - storePossibleCursor(opCtx, - dbInfo.primaryId(), - *response.shardHostAndPort, - cmdResponse.data, - nss, - Grid::get(opCtx)->getExecutorPool()->getArbitraryExecutor(), - Grid::get(opCtx)->getCursorManager(), - privileges)); - - CommandHelpers::filterCommandReplyForPassthrough(transformedResponse, out); - return true; -} - -bool cursorCommandPassthroughShardWithMinKeyChunk(OperationContext* opCtx, - const NamespaceString& nss, - const CachedCollectionRoutingInfo& routingInfo, - const BSONObj& cmdObj, - BSONObjBuilder* out, - const PrivilegeVector& privileges) { - auto response = executeCommandAgainstShardWithMinKeyChunk( - opCtx, - nss, - routingInfo, - CommandHelpers::filterCommandRequestForPassthrough(cmdObj), - ReadPreferenceSetting::get(opCtx), - Shard::RetryPolicy::kIdempotent); - const auto cmdResponse = uassertStatusOK(std::move(response.swResponse)); - - auto transformedResponse = uassertStatusOK( - storePossibleCursor(opCtx, - response.shardId, - *response.shardHostAndPort, - cmdResponse.data, - nss, - Grid::get(opCtx)->getExecutorPool()->getArbitraryExecutor(), - Grid::get(opCtx)->getCursorManager(), - privileges)); - - CommandHelpers::filterCommandReplyForPassthrough(transformedResponse, out); - return true; -} - -bool nonShardedCollectionCommandPassthrough(OperationContext* opCtx, - StringData dbName, - const NamespaceString& nss, - const CachedCollectionRoutingInfo& routingInfo, - const BSONObj& cmdObj, - Shard::RetryPolicy retryPolicy, - BSONObjBuilder* out) { - const StringData cmdName(cmdObj.firstElementFieldName()); - uassert(ErrorCodes::IllegalOperation, - str::stream() << "Can't do command: " << cmdName << " on a sharded collection", - !routingInfo.cm()); - - auto responses = scatterGatherVersionedTargetByRoutingTable(opCtx, - dbName, - nss, - routingInfo, - cmdObj, - ReadPreferenceSetting::get(opCtx), - retryPolicy, - {}, - {}); - invariant(responses.size() == 1); - - const auto cmdResponse = uassertStatusOK(std::move(responses.front().swResponse)); - const auto status = getStatusFromCommandResult(cmdResponse.data); - - uassert(ErrorCodes::IllegalOperation, - str::stream() << "Can't do command: " << cmdName << " on a sharded collection", - !ErrorCodes::isStaleShardVersionError(status)); - - out->appendElementsUnique(CommandHelpers::filterCommandReplyForPassthrough(cmdResponse.data)); - return status.isOK(); -} - -class NotAllowedOnShardedCollectionCmd : public BasicCommand { -protected: - NotAllowedOnShardedCollectionCmd(const char* n) : BasicCommand(n) {} - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kAlways; - } - - bool run(OperationContext* opCtx, - const std::string& dbName, - const BSONObj& cmdObj, - BSONObjBuilder& result) override { - const NamespaceString nss(parseNs(dbName, cmdObj)); - - const auto routingInfo = - uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); - uassert(ErrorCodes::IllegalOperation, - str::stream() << "can't do command: " << getName() << " on sharded collection", - !routingInfo.cm()); - - const auto primaryShard = routingInfo.db().primary(); - - // Here, we first filter the command before appending an UNSHARDED shardVersion, because - // "shardVersion" is one of the fields that gets filtered out. - BSONObj filteredCmdObj(applyReadWriteConcern( - opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj))); - BSONObj filteredCmdObjWithVersion( - appendShardVersion(filteredCmdObj, ChunkVersion::UNSHARDED())); - - auto commandResponse = uassertStatusOK(primaryShard->runCommandWithFixedRetryAttempts( - opCtx, - ReadPreferenceSetting::get(opCtx), - dbName, - primaryShard->isConfig() ? filteredCmdObj : filteredCmdObjWithVersion, - Shard::RetryPolicy::kIdempotent)); - - uassert(ErrorCodes::IllegalOperation, - str::stream() << "can't do command: " << getName() << " on a sharded collection", - !ErrorCodes::isStaleShardVersionError(commandResponse.commandStatus.code())); - - uassertStatusOK(commandResponse.commandStatus); - - if (!commandResponse.writeConcernStatus.isOK()) { - appendWriteConcernErrorToCmdResponse( - primaryShard->getId(), commandResponse.response["writeConcernError"], result); - } - result.appendElementsUnique( - CommandHelpers::filterCommandReplyForPassthrough(std::move(commandResponse.response))); - - return true; - } -}; - -class RenameCollectionCmd : public BasicCommand { -public: - RenameCollectionCmd() : BasicCommand("renameCollection") {} - - std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { - return CommandHelpers::parseNsFullyQualified(cmdObj); - } - - bool adminOnly() const override { - return true; - } - - bool supportsWriteConcern(const BSONObj& cmd) const override { - return true; - } - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kNever; - } - - Status checkAuthForCommand(Client* client, - const std::string& dbname, - const BSONObj& cmdObj) const override { - return rename_collection::checkAuthForRenameCollectionCommand(client, dbname, cmdObj); - } - - bool run(OperationContext* opCtx, - const std::string& dbName, - const BSONObj& cmdObj, - BSONObjBuilder& result) override { - auto renameRequest = - RenameCollectionCommand::parse(IDLParserErrorContext("renameCollection"), cmdObj); - auto fromNss = renameRequest.getCommandParameter(); - auto toNss = renameRequest.getTo(); - - uassert(ErrorCodes::InvalidNamespace, - str::stream() << "Invalid target namespace: " << toNss.ns(), - toNss.isValid()); - - const auto fromRoutingInfo = uassertStatusOK( - Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, fromNss)); - uassert(13138, "You can't rename a sharded collection", !fromRoutingInfo.cm()); - - const auto toRoutingInfo = uassertStatusOK( - Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, toNss)); - uassert(13139, "You can't rename to a sharded collection", !toRoutingInfo.cm()); - - uassert(13137, - "Source and destination collections must be on same shard", - fromRoutingInfo.db().primaryId() == toRoutingInfo.db().primaryId()); - - return nonShardedCollectionCommandPassthrough( - opCtx, - NamespaceString::kAdminDb, - fromNss, - fromRoutingInfo, - applyReadWriteConcern( - opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)), - Shard::RetryPolicy::kNoRetry, - &result); - } - -} renameCollectionCmd; - -class ConvertToCappedCmd : public BasicCommand { -public: - ConvertToCappedCmd() : BasicCommand("convertToCapped") {} - - bool supportsWriteConcern(const BSONObj& cmd) const override { - return true; - } - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kNever; - } - - std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { - return CommandHelpers::parseNsCollectionRequired(dbname, cmdObj).ns(); - } - - void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) const override { - ActionSet actions; - actions.addAction(ActionType::convertToCapped); - out->push_back(Privilege(parseResourcePattern(dbname, cmdObj), actions)); - } - - bool run(OperationContext* opCtx, - const std::string& dbName, - const BSONObj& cmdObj, - BSONObjBuilder& result) override { - const NamespaceString nss(parseNs(dbName, cmdObj)); - const auto routingInfo = - uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); - uassert(ErrorCodes::IllegalOperation, - "You can't convertToCapped a sharded collection", - !routingInfo.cm()); - - // convertToCapped creates a temp collection and renames it at the end. It will require - // special handling for create collection. - return nonShardedCollectionCommandPassthrough( - opCtx, - dbName, - nss, - routingInfo, - applyReadWriteConcern( - opCtx, this, CommandHelpers::filterCommandRequestForPassthrough(cmdObj)), - Shard::RetryPolicy::kIdempotent, - &result); - } - -} convertToCappedCmd; - -class SplitVectorCmd : public NotAllowedOnShardedCollectionCmd { -public: - SplitVectorCmd() : NotAllowedOnShardedCollectionCmd("splitVector") {} - - std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { - return CommandHelpers::parseNsFullyQualified(cmdObj); - } - - bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - - Status checkAuthForCommand(Client* client, - const std::string& dbname, - const BSONObj& cmdObj) const override { - if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( - ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), - ActionType::splitVector)) { - return Status(ErrorCodes::Unauthorized, "Unauthorized"); - } - return Status::OK(); - } - - bool run(OperationContext* opCtx, - const std::string& dbName, - const BSONObj& cmdObj, - BSONObjBuilder& result) override { - const NamespaceString nss(parseNs(dbName, cmdObj)); - uassert(ErrorCodes::IllegalOperation, - "Performing splitVector across dbs isn't supported via mongos", - nss.db() == dbName); - - return NotAllowedOnShardedCollectionCmd::run(opCtx, dbName, cmdObj, result); - } - -} splitVectorCmd; - -class CmdListCollections : public BasicCommand { -public: - CmdListCollections() : BasicCommand("listCollections") {} - - bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kAlways; - } - - bool maintenanceOk() const override { - return false; - } - - bool adminOnly() const override { - return false; - } - - Status checkAuthForCommand(Client* client, - const std::string& dbname, - const BSONObj& cmdObj) const final { - AuthorizationSession* authzSession = AuthorizationSession::get(client); - - if (authzSession->checkAuthorizedToListCollections(dbname, cmdObj).isOK()) { - return Status::OK(); - } - - return Status(ErrorCodes::Unauthorized, - str::stream() << "Not authorized to list collections on db: " << dbname); - } - - BSONObj rewriteCommandForListingOwnCollections(OperationContext* opCtx, - const std::string& dbName, - const BSONObj& cmdObj) { - mutablebson::Document rewrittenCmdObj(cmdObj); - mutablebson::Element ownCollections = - mutablebson::findFirstChildNamed(rewrittenCmdObj.root(), "authorizedCollections"); - - AuthorizationSession* authzSession = AuthorizationSession::get(opCtx->getClient()); - - // We must strip $ownCollections from the delegated command. - uassertStatusOK(ownCollections.remove()); - - BSONObj collectionFilter; - - // Extract and retain any previous filter - mutablebson::Element oldFilter = - mutablebson::findFirstChildNamed(rewrittenCmdObj.root(), "filter"); - - // Make a new filter, containing a $and array. - mutablebson::Element newFilter = rewrittenCmdObj.makeElementObject("filter"); - mutablebson::Element newFilterAnd = rewrittenCmdObj.makeElementArray("$and"); - uassertStatusOK(newFilter.pushBack(newFilterAnd)); - - mutablebson::Element newFilterOr = rewrittenCmdObj.makeElementArray("$or"); - mutablebson::Element newFilterOrObj = rewrittenCmdObj.makeElementObject(""); - uassertStatusOK(newFilterOrObj.pushBack(newFilterOr)); - uassertStatusOK(newFilterAnd.pushBack(newFilterOrObj)); - - // DB resource grants all non-system collections, so filter out system collections. - // This is done inside the $or, since some system collections might be granted specific - // privileges. - if (authzSession->isAuthorizedForAnyActionOnResource( - ResourcePattern::forDatabaseName(dbName))) { - mutablebson::Element systemCollectionsFilter = rewrittenCmdObj.makeElementObject( - "", BSON("name" << BSON("$regex" << BSONRegEx("^(?!system\\.)")))); - uassertStatusOK(newFilterOr.pushBack(systemCollectionsFilter)); - } - - // Compute the set of collection names which would be permissible to return. - std::set<std::string> collectionNames; - for (UserNameIterator nameIter = authzSession->getAuthenticatedUserNames(); nameIter.more(); - nameIter.next()) { - User* authUser = authzSession->lookupUser(*nameIter); - const User::ResourcePrivilegeMap& resourcePrivilegeMap = authUser->getPrivileges(); - for (const std::pair<ResourcePattern, Privilege>& resourcePrivilege : - resourcePrivilegeMap) { - const auto& resource = resourcePrivilege.first; - if (resource.isCollectionPattern() || - (resource.isExactNamespacePattern() && resource.databaseToMatch() == dbName)) { - collectionNames.emplace(resource.collectionToMatch().toString()); - } - } - } - - // Construct a new filter predicate which returns only collections we were found to - // have privileges for. - BSONObjBuilder predicateBuilder; - BSONObjBuilder nameBuilder(predicateBuilder.subobjStart("name")); - BSONArrayBuilder setBuilder(nameBuilder.subarrayStart("$in")); - - // Load the de-duplicated set into a BSON array - for (StringData collectionName : collectionNames) { - setBuilder << collectionName; - } - setBuilder.done(); - nameBuilder.done(); - - collectionFilter = predicateBuilder.obj(); - - // Filter the results by our collection names. - mutablebson::Element newFilterCollections = - rewrittenCmdObj.makeElementObject("", collectionFilter); - uassertStatusOK(newFilterOr.pushBack(newFilterCollections)); - - // If there was a pre-existing filter, compose it with our new one. - if (oldFilter.ok()) { - uassertStatusOK(oldFilter.remove()); - uassertStatusOK(newFilterAnd.pushBack(oldFilter)); - } - - // Attach our new composite filter back onto the listCollections command object. - uassertStatusOK(rewrittenCmdObj.root().pushBack(newFilter)); - - return rewrittenCmdObj.getObject(); - } - - bool run(OperationContext* opCtx, - const std::string& dbName, - const BSONObj& cmdObj, - BSONObjBuilder& result) override { - CommandHelpers::handleMarkKillOnClientDisconnect(opCtx); - - const auto nss(NamespaceString::makeListCollectionsNSS(dbName)); - - BSONObj newCmd = cmdObj; - - AuthorizationSession* authzSession = AuthorizationSession::get(opCtx->getClient()); - if (authzSession->getAuthorizationManager().isAuthEnabled() && - newCmd["authorizedCollections"].trueValue()) { - newCmd = rewriteCommandForListingOwnCollections(opCtx, dbName, cmdObj); - } - - auto dbInfoStatus = Grid::get(opCtx)->catalogCache()->getDatabase(opCtx, dbName); - if (!dbInfoStatus.isOK()) { - return appendEmptyResultSet(opCtx, result, dbInfoStatus.getStatus(), nss.ns()); - } - - return cursorCommandPassthroughPrimaryShard( - opCtx, - dbName, - dbInfoStatus.getValue(), - applyReadWriteConcern(opCtx, this, newCmd), - nss, - &result, - uassertStatusOK(AuthorizationSession::get(opCtx->getClient()) - ->checkAuthorizedToListCollections(dbName, cmdObj))); - } -} cmdListCollections; - -class CmdListIndexes : public BasicCommand { -public: - CmdListIndexes() : BasicCommand("listIndexes") {} - - std::string parseNs(const std::string& dbname, const BSONObj& cmdObj) const override { - return CommandHelpers::parseNsCollectionRequired(dbname, cmdObj).ns(); - } - - bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; - } - - AllowedOnSecondary secondaryAllowed(ServiceContext*) const override { - return AllowedOnSecondary::kAlways; - } - - bool maintenanceOk() const override { - return false; - } - - bool adminOnly() const override { - return false; - } - - Status checkAuthForCommand(Client* client, - const std::string& dbname, - const BSONObj& cmdObj) const override { - AuthorizationSession* authzSession = AuthorizationSession::get(client); - - // Check for the listIndexes ActionType on the database. - const NamespaceString ns(parseNs(dbname, cmdObj)); - - if (authzSession->isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns), - ActionType::listIndexes)) { - return Status::OK(); - } - - return Status(ErrorCodes::Unauthorized, - str::stream() - << "Not authorized to list indexes on collection: " << ns.coll()); - } - - bool run(OperationContext* opCtx, - const std::string& dbName, - const BSONObj& cmdObj, - BSONObjBuilder& result) override { - CommandHelpers::handleMarkKillOnClientDisconnect(opCtx); - - const NamespaceString nss(parseNs(dbName, cmdObj)); - const auto routingInfo = - uassertStatusOK(Grid::get(opCtx)->catalogCache()->getCollectionRoutingInfo(opCtx, nss)); - - return cursorCommandPassthroughShardWithMinKeyChunk( - opCtx, - nss, - routingInfo, - applyReadWriteConcern(opCtx, this, cmdObj), - &result, - {Privilege(ResourcePattern::forExactNamespace(nss), ActionType::listIndexes)}); - } - -} cmdListIndexes; - -} // namespace -} // namespace mongo diff --git a/src/mongo/s/commands/kill_sessions_remote.cpp b/src/mongo/s/commands/kill_sessions_remote.cpp index 6c3782cbb2b..d9b5ce26ccf 100644 --- a/src/mongo/s/commands/kill_sessions_remote.cpp +++ b/src/mongo/s/commands/kill_sessions_remote.cpp @@ -32,21 +32,19 @@ #include "mongo/platform/basic.h" #include "mongo/s/commands/kill_sessions_remote.h" -#include "mongo/s/commands/kill_sessions_remote_gen.h" #include "mongo/db/client.h" #include "mongo/db/kill_sessions_common.h" #include "mongo/db/operation_context.h" -#include "mongo/db/service_context.h" #include "mongo/executor/async_multicaster.h" #include "mongo/executor/task_executor_pool.h" #include "mongo/s/client/shard.h" #include "mongo/s/client/shard_registry.h" +#include "mongo/s/commands/cluster_commands_gen.h" #include "mongo/s/grid.h" #include "mongo/s/query/cluster_cursor_manager.h" namespace mongo { - namespace { /** @@ -112,10 +110,6 @@ Status killSessionsRemoteKillCursor(OperationContext* opCtx, } // namespace -/** - * This kill function (meant for mongos), kills matching local ops first, then fans out to all other - * nodes in the cluster to kill them as well. - */ SessionKiller::Result killSessionsRemote(OperationContext* opCtx, const SessionKiller::Matcher& matcher, SessionKiller::UniformRandomBitGenerator* urbg) { diff --git a/src/mongo/s/commands/kill_sessions_remote.h b/src/mongo/s/commands/kill_sessions_remote.h index ecd63341b9d..ef59d7769bd 100644 --- a/src/mongo/s/commands/kill_sessions_remote.h +++ b/src/mongo/s/commands/kill_sessions_remote.h @@ -29,14 +29,13 @@ #pragma once -#include "mongo/db/kill_sessions.h" - #include "mongo/db/session_killer.h" namespace mongo { /** - * The killSessions killer for running on mongos + * The killSessions killer for running on mongos. It kills matching local ops first, then fans out + * to all other nodes in the cluster to kill them as well. */ SessionKiller::Result killSessionsRemote(OperationContext* opCtx, const SessionKiller::Matcher& patterns, diff --git a/src/mongo/s/request_types/shard_collection.idl b/src/mongo/s/request_types/shard_collection.idl index 5df76c033e7..6440111a61b 100644 --- a/src/mongo/s/request_types/shard_collection.idl +++ b/src/mongo/s/request_types/shard_collection.idl @@ -35,38 +35,6 @@ imports: - "mongo/idl/basic_types.idl" structs: - shardCollection: - description: "The public shardCollection command on mongos" - strict: false - fields: - shardCollection: - type: namespacestring - description: "The namespace of the collection to shard in the form <database>.<collection>." - optional: true - shardcollection: - type: namespacestring - description: "The deprecated version of this command's name" - optional: true - key: - type: object - description: "The index specification document to use as the shard key." - unique: - type: bool - description: "Whether the shard key index should enforce a unique constraint" - default: false - numInitialChunks: - type: safeInt64 - description: "The number of chunks to create initially when sharding an empty collection with a hashed shard key." - default: 0 - presplitHashedZones: - type: bool - description: "True if the chunks should be pre-split based on the existing zones when sharding a collection with hashed shard key" - default: false - collation: - type: object - description: "The collation to use for the shard key index." - optional: true - ConfigsvrShardCollectionRequest: description: "The request format of the internal shardCollection command on the config server" strict: false @@ -115,7 +83,7 @@ structs: description: "The UUID of the collection that just got sharded." optional: true - ShardsvrShardCollection: + ShardsvrShardCollectionRequest: description: "The internal shardCollection command on a primary shard" strict: false fields: @@ -162,15 +130,3 @@ structs: type: uuid description: "The UUID of the collection that just got sharded." optional: true - - ConfigsvrCommitShardCollection: - description: "The internal commitShardCollection command on the config server" - strict: false - fields: - _configsvrCommitShardCollection: - type: string - description: "The name of the collection that just got sharded." - collectionUUID: - type: uuid - description: "The UUID of the collection that just got sharded." - optional: true |