From f14037e54577ce79cec00e06735f914c01b3f80e Mon Sep 17 00:00:00 2001 From: Hugh Han Date: Wed, 26 Jul 2017 13:28:57 -0400 Subject: SERVER-30324 Move cluster_remove_shard_cmd to mongod --- .../db/s/config/configsvr_remove_shard_command.cpp | 106 ++++++++++++++++++++- 1 file changed, 105 insertions(+), 1 deletion(-) (limited to 'src/mongo/db') diff --git a/src/mongo/db/s/config/configsvr_remove_shard_command.cpp b/src/mongo/db/s/config/configsvr_remove_shard_command.cpp index 5ac9d2dc224..d24516b0a9c 100644 --- a/src/mongo/db/s/config/configsvr_remove_shard_command.cpp +++ b/src/mongo/db/s/config/configsvr_remove_shard_command.cpp @@ -42,6 +42,7 @@ #include "mongo/s/catalog/sharding_catalog_manager.h" #include "mongo/s/catalog/type_database.h" #include "mongo/s/catalog_cache.h" +#include "mongo/s/client/shard_registry.h" #include "mongo/s/grid.h" #include "mongo/util/log.h" #include "mongo/util/scopeguard.h" @@ -65,7 +66,7 @@ public: } virtual bool supportsWriteConcern(const BSONObj& cmd) const override { - return false; + return true; } virtual void help(std::stringstream& help) const override { @@ -73,11 +74,114 @@ public: "directly. Removes a shard from the cluster."; } + Status checkAuthForCommand(Client* client, + const std::string& dbname, + const BSONObj& cmdObj) override { + if (!AuthorizationSession::get(client)->isAuthorizedForActionsOnResource( + ResourcePattern::forClusterResource(), ActionType::internal)) { + return Status(ErrorCodes::Unauthorized, "Unauthorized"); + } + return Status::OK(); + } + bool run(OperationContext* opCtx, const std::string& dbname, const BSONObj& cmdObj, BSONObjBuilder& result) { + uassert(ErrorCodes::IllegalOperation, + "_configsvrRemoveShard can only be run on config servers", + serverGlobalParams.clusterRole == ClusterRole::ConfigServer); + + uassert(ErrorCodes::TypeMismatch, + str::stream() << "Field '" << cmdObj.firstElement().fieldName() + << "' must be of type string", + cmdObj.firstElement().type() == BSONType::String); + const std::string target = cmdObj.firstElement().str(); + + const auto shardStatus = grid.shardRegistry()->getShard(opCtx, ShardId(target)); + if (!shardStatus.isOK()) { + std::string msg(str::stream() << "Could not drop shard '" << target + << "' because it does not exist"); + log() << msg; + return appendCommandStatus(result, Status(ErrorCodes::ShardNotFound, msg)); + } + const auto shard = shardStatus.getValue(); + + const auto shardingCatalogManager = ShardingCatalogManager::get(opCtx); + + StatusWith removeShardResult = + shardingCatalogManager->removeShard(opCtx, shard->getId()); + if (!removeShardResult.isOK()) { + return appendCommandStatus(result, removeShardResult.getStatus()); + } + + std::vector databases; + Status status = + shardingCatalogManager->getDatabasesForShard(opCtx, shard->getId(), &databases); + if (!status.isOK()) { + return appendCommandStatus(result, status); + } + + // Get BSONObj containing: + // 1) note about moving or dropping databases in a shard + // 2) list of databases (excluding 'local' database) that need to be moved + BSONObj dbInfo; + { + BSONObjBuilder dbInfoBuilder; + dbInfoBuilder.append("note", "you need to drop or movePrimary these databases"); + BSONArrayBuilder dbs(dbInfoBuilder.subarrayStart("dbsToMove")); + for (std::vector::const_iterator it = databases.begin(); + it != databases.end(); + it++) { + if (*it != "local") { + dbs.append(*it); + } + } + dbs.doneFast(); + dbInfo = dbInfoBuilder.obj(); + } + + // TODO: Standardize/Seperate how we append to the result object + switch (removeShardResult.getValue()) { + case ShardDrainingStatus::STARTED: + result.append("msg", "draining started successfully"); + result.append("state", "started"); + result.append("shard", shard->getId().toString()); + result.appendElements(dbInfo); + break; + case ShardDrainingStatus::ONGOING: { + std::vector chunks; + Status status = Grid::get(opCtx)->catalogClient()->getChunks( + opCtx, + BSON(ChunkType::shard(shard->getId().toString())), + BSONObj(), + boost::none, // return all + &chunks, + nullptr, + repl::ReadConcernLevel::kMajorityReadConcern); + if (!status.isOK()) { + return appendCommandStatus(result, status); + } + + result.append("msg", "draining ongoing"); + result.append("state", "ongoing"); + { + BSONObjBuilder inner; + inner.append("chunks", static_cast(chunks.size())); + inner.append("dbs", static_cast(databases.size())); + BSONObj b = inner.obj(); + result.append("remaining", b); + } + result.appendElements(dbInfo); + break; + } + case ShardDrainingStatus::COMPLETED: + result.append("msg", "removeshard completed successfully"); + result.append("state", "completed"); + result.append("shard", shard->getId().toString()); + } + return true; } -- cgit v1.2.1