diff options
Diffstat (limited to 'src/mongo')
-rw-r--r-- | src/mongo/SConscript | 1 | ||||
-rw-r--r-- | src/mongo/s/commands/SConscript | 13 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_add_shard_cmd.cpp | 141 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_get_prev_error_cmd.cpp | 80 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_get_shard_version_cmd.cpp (renamed from src/mongo/s/commands/cluster_get_shard_version.cpp) | 0 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_is_db_grid_cmd.cpp | 72 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_is_master_cmd.cpp | 87 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_list_shards_cmd.cpp | 97 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_move_chunk_cmd.cpp | 4 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_remove_shard_cmd.cpp | 265 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_reset_error_cmd.cpp (renamed from src/mongo/s/commands/cluster_reset_error.cpp) | 0 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_whats_my_uri_cmd.cpp | 76 | ||||
-rw-r--r-- | src/mongo/s/commands/cluster_write_cmd.cpp | 352 | ||||
-rw-r--r-- | src/mongo/s/commands_admin.cpp | 487 |
14 files changed, 994 insertions, 681 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript index 404cce94c19..fb8b81e15fd 100644 --- a/src/mongo/SConscript +++ b/src/mongo/SConscript @@ -854,7 +854,6 @@ env.Library('coreshard', env.Library('mongoscore', [ 's/strategy.cpp', - 's/commands_admin.cpp', 's/commands_public.cpp', 's/request.cpp', 's/client_info.cpp', diff --git a/src/mongo/s/commands/SConscript b/src/mongo/s/commands/SConscript index bcdb94d3088..6b691d97f07 100644 --- a/src/mongo/s/commands/SConscript +++ b/src/mongo/s/commands/SConscript @@ -5,25 +5,32 @@ Import("env") env.Library( target='cluster_commands', source=[ - 'cluster_explain_cmd.cpp', + 'cluster_add_shard_cmd.cpp', 'cluster_enable_sharding_cmd.cpp', + 'cluster_explain_cmd.cpp', 'cluster_find_cmd.cpp', 'cluster_flush_router_config_cmd.cpp', 'cluster_fsync_cmd.cpp', 'cluster_get_last_error_cmd.cpp', - 'cluster_get_shard_version.cpp', + 'cluster_get_prev_error_cmd.cpp', + 'cluster_get_shard_version_cmd.cpp', 'cluster_index_filter_cmd.cpp', + 'cluster_is_db_grid_cmd.cpp', + 'cluster_is_master_cmd.cpp', 'cluster_list_databases_cmd.cpp', + 'cluster_list_shards_cmd.cpp', 'cluster_merge_chunks_cmd.cpp', 'cluster_move_chunk_cmd.cpp', 'cluster_move_primary_cmd.cpp', 'cluster_netstat_cmd.cpp', 'cluster_plan_cache_cmd.cpp', + 'cluster_remove_shard_cmd.cpp', 'cluster_repl_set_get_status_cmd.cpp', - 'cluster_reset_error.cpp', + 'cluster_reset_error_cmd.cpp', 'cluster_shard_collection_cmd.cpp', 'cluster_shutdown_cmd.cpp', 'cluster_split_collection_cmd.cpp', + 'cluster_whats_my_uri_cmd.cpp', 'cluster_write_cmd.cpp', ], LIBDEPS=[ diff --git a/src/mongo/s/commands/cluster_add_shard_cmd.cpp b/src/mongo/s/commands/cluster_add_shard_cmd.cpp new file mode 100644 index 00000000000..e80b9e76157 --- /dev/null +++ b/src/mongo/s/commands/cluster_add_shard_cmd.cpp @@ -0,0 +1,141 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand + +#include "mongo/platform/basic.h" + +#include <vector> + +#include "mongo/db/audit.h" +#include "mongo/db/commands.h" +#include "mongo/s/grid.h" +#include "mongo/s/type_shard.h" +#include "mongo/util/log.h" + +namespace mongo { + + using std::string; + +namespace { + + class AddShardCmd : public Command { + public: + AddShardCmd() : Command("addShard", false, "addshard") { } + + virtual bool slaveOk() const { + return true; + } + + virtual bool adminOnly() const { + return true; + } + + virtual bool isWriteCommandForConfigServer() const { + return false; + } + + virtual void help(std::stringstream& help) const { + help << "add a new shard to the system"; + } + + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) { + + ActionSet actions; + actions.addAction(ActionType::addShard); + out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + } + + virtual bool run(OperationContext* txn, + const std::string& dbname, + BSONObj& cmdObj, + int options, + std::string& errmsg, + BSONObjBuilder& result, + bool fromRepl) { + + // get replica set component hosts + ConnectionString servers = ConnectionString::parse( + cmdObj.firstElement().valuestrsafe(), errmsg); + if (!errmsg.empty()) { + log() << "addshard request " << cmdObj << " failed: " << errmsg; + return false; + } + + // using localhost in server names implies every other process must use localhost addresses too + std::vector<HostAndPort> serverAddrs = servers.getServers(); + for (size_t i = 0; i < serverAddrs.size(); i++) { + if (serverAddrs[i].isLocalHost() != grid.allowLocalHost()) { + errmsg = str::stream() << + "Can't use localhost as a shard since all shards need to" << + " communicate. Either use all shards and configdbs in localhost" << + " or all in actual IPs. host: " << serverAddrs[i].toString() << + " isLocalHost:" << serverAddrs[i].isLocalHost(); + + log() << "addshard request " << cmdObj + << " failed: attempt to mix localhosts and IPs"; + return false; + } + + // it's fine if mongods of a set all use default port + if (!serverAddrs[i].hasPort()) { + serverAddrs[i] = HostAndPort(serverAddrs[i].host(), + ServerGlobalParams::ShardServerPort); + } + } + + // name is optional; addShard will provide one if needed + string name = ""; + if (cmdObj["name"].type() == String) { + name = cmdObj["name"].valuestrsafe(); + } + + // maxSize is the space usage cap in a shard in MBs + long long maxSize = 0; + if (cmdObj[ShardType::maxSize()].isNumber()) { + maxSize = cmdObj[ShardType::maxSize()].numberLong(); + } + + audit::logAddShard(ClientBasic::getCurrent(), name, servers.toString(), maxSize); + + if (!grid.addShard(&name, servers, maxSize, errmsg)) { + log() << "addshard request " << cmdObj << " failed: " << errmsg; + return false; + } + + result << "shardAdded" << name; + return true; + } + + } addShard; + + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_get_prev_error_cmd.cpp b/src/mongo/s/commands/cluster_get_prev_error_cmd.cpp new file mode 100644 index 00000000000..2e61db1683a --- /dev/null +++ b/src/mongo/s/commands/cluster_get_prev_error_cmd.cpp @@ -0,0 +1,80 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/platform/basic.h" + +#include <set> +#include <string> + +#include "mongo/db/commands.h" +#include "mongo/db/lasterror.h" +#include "mongo/s/client/shard_connection.h" +#include "mongo/s/client_info.h" + +namespace mongo { +namespace { + + class GetPrevErrorCmd : public Command { + public: + GetPrevErrorCmd() : Command("getPrevError", false, "getpreverror") { } + + virtual bool isWriteCommandForConfigServer() const { + return false; + } + + virtual bool slaveOk() const { + return true; + } + + virtual void help(std::stringstream& help) const { + help << "get previous error (since last reseterror command)"; + } + + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) { + + // No auth required + } + + virtual bool run(OperationContext* txn, + const std::string& dbname, + BSONObj& cmdObj, + int options, + std::string& errmsg, + BSONObjBuilder& result, + bool fromRepl) { + + errmsg += "getpreverror not supported for sharded environments"; + return false; + } + + } cmdGetPrevError; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_get_shard_version.cpp b/src/mongo/s/commands/cluster_get_shard_version_cmd.cpp index 6137310dd3e..6137310dd3e 100644 --- a/src/mongo/s/commands/cluster_get_shard_version.cpp +++ b/src/mongo/s/commands/cluster_get_shard_version_cmd.cpp diff --git a/src/mongo/s/commands/cluster_is_db_grid_cmd.cpp b/src/mongo/s/commands/cluster_is_db_grid_cmd.cpp new file mode 100644 index 00000000000..e84b079937b --- /dev/null +++ b/src/mongo/s/commands/cluster_is_db_grid_cmd.cpp @@ -0,0 +1,72 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/platform/basic.h" + +#include "mongo/db/commands.h" +#include "mongo/util/net/sock.h" + +namespace mongo { +namespace { + + class IsDbGridCmd : public Command { + public: + IsDbGridCmd() : Command("isdbgrid") { } + + virtual bool isWriteCommandForConfigServer() const { + return false; + } + + virtual bool slaveOk() const { + return true; + } + + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) { + + // No auth required + } + + virtual bool run(OperationContext* txn, + const std::string& dbname, + BSONObj& cmdObj, + int options, + std::string& errmsg, + BSONObjBuilder& result, + bool fromRepl) { + + result.append("isdbgrid", 1); + result.append("hostname", getHostNameCached()); + return true; + } + + } isdbGrid; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_is_master_cmd.cpp b/src/mongo/s/commands/cluster_is_master_cmd.cpp new file mode 100644 index 00000000000..6bc41b14cc3 --- /dev/null +++ b/src/mongo/s/commands/cluster_is_master_cmd.cpp @@ -0,0 +1,87 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/platform/basic.h" + +#include "mongo/db/commands.h" +#include "mongo/db/wire_version.h" +#include "mongo/s/write_ops/batched_command_request.h" + +namespace mongo { +namespace { + + class CmdIsMaster : public Command { + public: + CmdIsMaster() : Command("isMaster", false, "ismaster") { } + + virtual bool isWriteCommandForConfigServer() const { + return false; + } + + virtual bool slaveOk() const { + return true; + } + + virtual void help(std::stringstream& help) const { + help << "test if this is master half of a replica pair"; + } + + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) { + + // No auth required + } + + virtual bool run(OperationContext* txn, + const std::string& dbname, + BSONObj& cmdObj, + int options, + std::string& errmsg, + BSONObjBuilder& result, + bool fromRepl) { + + result.appendBool("ismaster", true); + result.append("msg", "isdbgrid"); + result.appendNumber("maxBsonObjectSize", BSONObjMaxUserSize); + result.appendNumber("maxMessageSizeBytes", MaxMessageSizeBytes); + result.appendNumber("maxWriteBatchSize", BatchedCommandRequest::kMaxWriteBatchSize); + result.appendDate("localTime", jsTime()); + + // Mongos tries to keep exactly the same version range of the server for which + // it is compiled. + result.append("maxWireVersion", maxWireVersion); + result.append("minWireVersion", minWireVersion); + + return true; + } + + } isMaster; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_list_shards_cmd.cpp b/src/mongo/s/commands/cluster_list_shards_cmd.cpp new file mode 100644 index 00000000000..3cccb6232a8 --- /dev/null +++ b/src/mongo/s/commands/cluster_list_shards_cmd.cpp @@ -0,0 +1,97 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/platform/basic.h" + +#include <vector> + +#include "mongo/client/connpool.h" +#include "mongo/db/commands.h" +#include "mongo/s/config.h" +#include "mongo/s/type_shard.h" + +namespace mongo { +namespace { + + class ListShardsCmd : public Command { + public: + ListShardsCmd() : Command("listShards", false, "listshards") { } + + virtual bool slaveOk() const { + return true; + } + + virtual bool adminOnly() const { + return true; + } + + virtual bool isWriteCommandForConfigServer() const { + return false; + } + + virtual void help(std::stringstream& help) const { + help << "list all shards of the system"; + } + + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) { + + ActionSet actions; + actions.addAction(ActionType::listShards); + out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + } + + virtual bool run(OperationContext* txn, + const std::string& dbname, + BSONObj& cmdObj, + int options, + std::string& errmsg, + BSONObjBuilder& result, + bool fromRepl) { + + std::vector<BSONObj> all; + + ScopedDbConnection conn(configServer.getPrimary().getConnString(), 30); + std::auto_ptr<DBClientCursor> cursor = conn->query(ShardType::ConfigNS, BSONObj()); + while (cursor->more()) { + BSONObj o = cursor->next(); + all.push_back(o); + } + + result.append("shards", all); + + conn.done(); + + return true; + } + + } listShards; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_move_chunk_cmd.cpp b/src/mongo/s/commands/cluster_move_chunk_cmd.cpp index 51588058c32..10623a1c29e 100644 --- a/src/mongo/s/commands/cluster_move_chunk_cmd.cpp +++ b/src/mongo/s/commands/cluster_move_chunk_cmd.cpp @@ -176,7 +176,7 @@ namespace { // Bounds if (!info->getShardKeyPattern().isShardKey(bounds[0].Obj()) - || !info->getShardKeyPattern().isShardKey(bounds[1].Obj())) { + || !info->getShardKeyPattern().isShardKey(bounds[1].Obj())) { errmsg = str::stream() << "shard key bounds " << "[" << bounds[0].Obj() << "," << bounds[1].Obj() << ")" << " are not valid for shard key pattern " @@ -251,7 +251,7 @@ namespace { return true; } - } moveChunkCmd; + } moveChunk; } // namespace } // namespace mongo diff --git a/src/mongo/s/commands/cluster_remove_shard_cmd.cpp b/src/mongo/s/commands/cluster_remove_shard_cmd.cpp new file mode 100644 index 00000000000..d93a8152a88 --- /dev/null +++ b/src/mongo/s/commands/cluster_remove_shard_cmd.cpp @@ -0,0 +1,265 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand + +#include "mongo/platform/basic.h" + +#include <string> + +#include "mongo/client/connpool.h" +#include "mongo/client/replica_set_monitor.h" +#include "mongo/db/audit.h" +#include "mongo/db/commands.h" +#include "mongo/s/client/shard_connection.h" +#include "mongo/s/cluster_write.h" +#include "mongo/s/config.h" +#include "mongo/s/grid.h" +#include "mongo/s/shard.h" +#include "mongo/s/type_chunk.h" +#include "mongo/s/type_database.h" +#include "mongo/s/type_shard.h" +#include "mongo/util/log.h" + +namespace mongo { + + using std::string; + +namespace { + + BSONObj buildRemoveLogEntry(Shard s, bool isDraining) { + BSONObjBuilder details; + details.append("shard", s.getName()); + details.append("isDraining", isDraining); + + return details.obj(); + } + + + class RemoveShardCmd : public Command { + public: + RemoveShardCmd() : Command("removeShard", false, "removeshard") { } + + virtual bool slaveOk() const { + return true; + } + + virtual bool adminOnly() const { + return true; + } + + virtual bool isWriteCommandForConfigServer() const { + return false; + } + + virtual void help(std::stringstream& help) const { + help << "remove a shard from the system."; + } + + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) { + + ActionSet actions; + actions.addAction(ActionType::removeShard); + out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); + } + + virtual bool run(OperationContext* txn, + const std::string& dbname, + BSONObj& cmdObj, + int options, + std::string& errmsg, + BSONObjBuilder& result, + bool fromRepl) { + + const string target = cmdObj.firstElement().valuestrsafe(); + + Shard s = Shard::make(target); + if (!grid.knowAboutShard(s.getConnString())) { + errmsg = "unknown shard"; + return false; + } + + ScopedDbConnection conn(configServer.getPrimary().getConnString(), 30); + + if (conn->count(ShardType::ConfigNS, + BSON(ShardType::name() << NE << s.getName() + << ShardType::draining(true)))) { + conn.done(); + errmsg = "Can't have more than one draining shard at a time"; + return false; + } + + if (conn->count(ShardType::ConfigNS, + BSON(ShardType::name() << NE << s.getName())) == 0) { + conn.done(); + errmsg = "Can't remove last shard"; + return false; + } + + BSONObj primaryDoc = + BSON(DatabaseType::name.ne("local") << DatabaseType::primary(s.getName())); + + BSONObj dbInfo; // appended at end of result on success + { + boost::scoped_ptr<DBClientCursor> cursor(conn->query(DatabaseType::ConfigNS, + primaryDoc)); + if (cursor->more()) { + // Skip block and allocations if empty + BSONObjBuilder dbInfoBuilder; + dbInfoBuilder.append("note", + "you need to drop or movePrimary these databases"); + + BSONArrayBuilder dbs(dbInfoBuilder.subarrayStart("dbsToMove")); + while (cursor->more()){ + BSONObj db = cursor->nextSafe(); + dbs.append(db[DatabaseType::name()]); + } + dbs.doneFast(); + + dbInfo = dbInfoBuilder.obj(); + } + } + + // If the server is not yet draining chunks, put it in draining mode. + BSONObj searchDoc = BSON(ShardType::name() << s.getName()); + BSONObj drainingDoc = + BSON(ShardType::name() << s.getName() << ShardType::draining(true)); + + BSONObj shardDoc = conn->findOne(ShardType::ConfigNS, drainingDoc); + if (shardDoc.isEmpty()) { + log() << "going to start draining shard: " << s.getName(); + BSONObj newStatus = BSON("$set" << BSON(ShardType::draining(true))); + + Status status = clusterUpdate(ShardType::ConfigNS, + searchDoc, + newStatus, + false, + false, + NULL); + if (!status.isOK()) { + errmsg = status.reason(); + log() << "error starting remove shard: " << s.getName() + << " err: " << errmsg; + return false; + } + + BSONObj primaryLocalDoc = BSON(DatabaseType::name("local") << + DatabaseType::primary(s.getName())); + PRINT(primaryLocalDoc); + + if (conn->count(DatabaseType::ConfigNS, primaryLocalDoc)) { + log() << "This shard is listed as primary of local db. Removing entry."; + + Status status = clusterDelete(DatabaseType::ConfigNS, + BSON(DatabaseType::name("local")), + 0, + NULL); + if (!status.isOK()) { + log() << "error removing local db: " + << status.reason(); + return false; + } + } + + Shard::reloadShardInfo(); + + result.append("msg", "draining started successfully"); + result.append("state", "started"); + result.append("shard", s.getName()); + result.appendElements(dbInfo); + + conn.done(); + + // Record start in changelog + configServer.logChange("removeShard.start", + "", + buildRemoveLogEntry(s, true)); + + return true; + } + + // If the server has been completely drained, remove it from the ConfigDB. Check not + // only for chunks but also databases. + BSONObj shardIDDoc = BSON(ChunkType::shard(shardDoc[ShardType::name()].str())); + long long chunkCount = conn->count(ChunkType::ConfigNS, shardIDDoc); + long long dbCount = conn->count(DatabaseType::ConfigNS, primaryDoc); + + if ((chunkCount == 0) && (dbCount == 0)) { + log() << "going to remove shard: " << s.getName(); + audit::logRemoveShard(ClientBasic::getCurrent(), s.getName()); + + Status status = clusterDelete(ShardType::ConfigNS, + searchDoc, + 0, + NULL); + if (!status.isOK()) { + errmsg = status.reason(); + log() << "error concluding remove shard: " << s.getName() + << " err: " << errmsg; + return false; + } + + const string shardName = shardDoc[ShardType::name()].str(); + Shard::removeShard(shardName); + shardConnectionPool.removeHost(shardName); + ReplicaSetMonitor::remove(shardName, true); + + Shard::reloadShardInfo(); + + result.append("msg", "removeshard completed successfully"); + result.append("state", "completed"); + result.append("shard", s.getName()); + + conn.done(); + + // Record finish in changelog + configServer.logChange("removeShard", "", buildRemoveLogEntry(s, false)); + + return true; + } + + // If the server is already in draining mode, just report on its progress. + // Report on databases (not just chunks) that are left too. + result.append("msg", "draining ongoing"); + result.append("state", "ongoing"); + BSONObjBuilder inner; + inner.append("chunks", chunkCount); + inner.append("dbs", dbCount); + result.append("remaining", inner.obj()); + result.appendElements(dbInfo); + + conn.done(); + return true; + } + + } removeShardCmd; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_reset_error.cpp b/src/mongo/s/commands/cluster_reset_error_cmd.cpp index c3096d367b1..c3096d367b1 100644 --- a/src/mongo/s/commands/cluster_reset_error.cpp +++ b/src/mongo/s/commands/cluster_reset_error_cmd.cpp diff --git a/src/mongo/s/commands/cluster_whats_my_uri_cmd.cpp b/src/mongo/s/commands/cluster_whats_my_uri_cmd.cpp new file mode 100644 index 00000000000..2f9c3a618c5 --- /dev/null +++ b/src/mongo/s/commands/cluster_whats_my_uri_cmd.cpp @@ -0,0 +1,76 @@ +/** + * Copyright (C) 2015 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/platform/basic.h" + +#include "mongo/db/commands.h" +#include "mongo/s/client_info.h" +#include "mongo/util/net/sock.h" + +namespace mongo { +namespace { + + class WhatsMyUriCmd : public Command { + public: + WhatsMyUriCmd() : Command("whatsmyuri") { } + + virtual bool slaveOk() const { + return true; + } + + virtual bool isWriteCommandForConfigServer() const { + return false; + } + + virtual void help(std::stringstream &help) const { + help << "{whatsmyuri:1}"; + } + + virtual void addRequiredPrivileges(const std::string& dbname, + const BSONObj& cmdObj, + std::vector<Privilege>* out) { + + // No auth required + } + + virtual bool run(OperationContext* txn, + const std::string& dbname, + BSONObj& cmdObj, + int options, + std::string& errmsg, + BSONObjBuilder& result, + bool fromRepl) { + + result << "you" << ClientInfo::get()->getRemote().toString(); + return true; + } + + } whatsMyUriCmd; + +} // namespace +} // namespace mongo diff --git a/src/mongo/s/commands/cluster_write_cmd.cpp b/src/mongo/s/commands/cluster_write_cmd.cpp index 1b8828a4824..b6376980dbb 100644 --- a/src/mongo/s/commands/cluster_write_cmd.cpp +++ b/src/mongo/s/commands/cluster_write_cmd.cpp @@ -28,7 +28,6 @@ #include "mongo/platform/basic.h" -#include "mongo/base/init.h" #include "mongo/base/error_codes.h" #include "mongo/db/client_basic.h" #include "mongo/db/commands.h" @@ -50,6 +49,8 @@ namespace mongo { using std::stringstream; using std::vector; +namespace { + /** * Base class for mongos write commands. Cluster write commands support batch writes and write * concern, and return per-item error information. All cluster write commands use the entry @@ -58,31 +59,32 @@ namespace mongo { * Batch execution (targeting and dispatching) is performed by the BatchWriteExec class. */ class ClusterWriteCmd : public Command { - MONGO_DISALLOW_COPYING(ClusterWriteCmd); public: - virtual ~ClusterWriteCmd() { + } - bool slaveOk() const { + virtual bool slaveOk() const { return false; } - bool isWriteCommandForConfigServer() const { return false; } + virtual bool isWriteCommandForConfigServer() const { + return false; + } - Status checkAuthForCommand( ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj ) { + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { - Status status = auth::checkAuthForWriteCommand( client->getAuthorizationSession(), - _writeType, - NamespaceString( parseNs( dbname, - cmdObj ) ), - cmdObj ); + Status status = auth::checkAuthForWriteCommand(client->getAuthorizationSession(), + _writeType, + NamespaceString(parseNs(dbname, + cmdObj)), + cmdObj); // TODO: Remove this when we standardize GLE reporting from commands - if ( !status.isOK() ) { - setLastError( status.code(), status.reason().c_str() ); + if (!status.isOK()) { + setLastError(status.code(), status.reason().c_str()); } return status; @@ -92,215 +94,189 @@ namespace mongo { const std::string& dbname, const BSONObj& cmdObj, ExplainCommon::Verbosity verbosity, - BSONObjBuilder* out) const; - - // Cluster write command entry point. - bool run(OperationContext* txn, const string& dbname, - BSONObj& cmdObj, - int options, - string& errmsg, - BSONObjBuilder& result, - bool fromRepl ); - - protected: - - /** - * Instantiates a command that can be invoked by "name", which will be capable of issuing - * write batches of type "writeType", and will require privilege "action" to run. - */ - ClusterWriteCmd( StringData name, BatchedCommandRequest::BatchType writeType ) : - Command( name ), _writeType( writeType ) { - } - - private: - - // Type of batch (e.g. insert). - BatchedCommandRequest::BatchType _writeType; - }; + BSONObjBuilder* out) const { - class ClusterCmdInsert : public ClusterWriteCmd { - MONGO_DISALLOW_COPYING(ClusterCmdInsert); - public: - ClusterCmdInsert() : - ClusterWriteCmd( "insert", BatchedCommandRequest::BatchType_Insert ) { - } + BatchedCommandRequest request(_writeType); - void help( stringstream& help ) const { - help << "insert documents"; - } - }; + string errMsg; + if (!request.parseBSON(cmdObj, &errMsg) || !request.isValid(&errMsg)) { + return Status(ErrorCodes::FailedToParse, errMsg); + } - class ClusterCmdUpdate : public ClusterWriteCmd { - MONGO_DISALLOW_COPYING(ClusterCmdUpdate); - public: - ClusterCmdUpdate() : - ClusterWriteCmd( "update", BatchedCommandRequest::BatchType_Update ) { - } + // Fixup the namespace to be a full ns internally + const NamespaceString nss(dbname, request.getNS()); + request.setNS(nss.ns()); - void help( stringstream& help ) const { - help << "update documents"; - } - }; + // We can only explain write batches of size 1. + if (request.sizeWriteOps() != 1U) { + return Status(ErrorCodes::InvalidLength, + "explained write batches must be of size 1"); + } - class ClusterCmdDelete : public ClusterWriteCmd { - MONGO_DISALLOW_COPYING(ClusterCmdDelete); - public: - ClusterCmdDelete() : - ClusterWriteCmd( "delete", BatchedCommandRequest::BatchType_Delete ) { - } + BSONObjBuilder explainCmdBob; + ClusterExplain::wrapAsExplain(cmdObj, verbosity, &explainCmdBob); + + // We will time how long it takes to run the commands on the shards. + Timer timer; + + // Target the command to the shards based on the singleton batch item. + BatchItemRef targetingBatchItem(&request, 0); + vector<Strategy::CommandResult> shardResults; + Status status = STRATEGY->commandOpWrite(dbname, + explainCmdBob.obj(), + targetingBatchItem, + &shardResults); + if (!status.isOK()) { + return status; + } - void help( stringstream& help ) const { - help << "delete documents"; + return ClusterExplain::buildExplainResult(shardResults, + ClusterExplain::kWriteOnShards, + timer.millis(), + out); } - }; - - // - // Cluster write command implementation(s) below - // - - bool ClusterWriteCmd::run(OperationContext* txn, const string& dbName, - BSONObj& cmdObj, - int options, - string& errMsg, - BSONObjBuilder& result, - bool ) { - BatchedCommandRequest request( _writeType ); - BatchedCommandResponse response; - ClusterWriter writer( true /* autosplit */, 0 /* timeout */ ); - - // NOTE: Sometimes this command is invoked with LE disabled for legacy writes - LastError* cmdLastError = lastError.get( false ); + virtual bool run(OperationContext* txn, + const string& dbname, + BSONObj& cmdObj, + int options, + string& errmsg, + BSONObjBuilder& result, + bool fromRepl) { + + BatchedCommandRequest request(_writeType); + BatchedCommandResponse response; + + ClusterWriter writer(true, 0); + + // NOTE: Sometimes this command is invoked with LE disabled for legacy writes + LastError* cmdLastError = lastError.get(false); + + { + // Disable the last error object for the duration of the write + LastError::Disabled disableLastError(cmdLastError); + + // TODO: if we do namespace parsing, push this to the type + if (!request.parseBSON(cmdObj, &errmsg) || !request.isValid(&errmsg)) { + // Batch parse failure + response.setOk(false); + response.setErrCode(ErrorCodes::FailedToParse); + response.setErrMessage(errmsg); + } + else { + // Fixup the namespace to be a full ns internally + const NamespaceString nss(dbname, request.getNS()); + request.setNSS(nss); + + writer.write(request, &response); + } + + dassert(response.isValid(NULL)); + } - { - // Disable the last error object for the duration of the write - LastError::Disabled disableLastError( cmdLastError ); + if (cmdLastError) { + // Populate the lastError object based on the write response + cmdLastError->reset(); + batchErrorToLastError(request, response, cmdLastError); + } - // TODO: if we do namespace parsing, push this to the type - if ( !request.parseBSON( cmdObj, &errMsg ) || !request.isValid( &errMsg ) ) { + size_t numAttempts; - // Batch parse failure - response.setOk( false ); - response.setErrCode( ErrorCodes::FailedToParse ); - response.setErrMessage( errMsg ); + if (!response.getOk()) { + numAttempts = 0; + } + else if (request.getOrdered() && response.isErrDetailsSet()) { + // Add one failed attempt + numAttempts = response.getErrDetailsAt(0)->getIndex() + 1; } else { + numAttempts = request.sizeWriteOps(); + } - // Fixup the namespace to be a full ns internally - NamespaceString nss( dbName, request.getNS() ); - request.setNSS( nss ); + // TODO: increase opcounters by more than one + if (_writeType == BatchedCommandRequest::BatchType_Insert) { + for (size_t i = 0; i < numAttempts; ++i) { + globalOpCounters.gotInsert(); + } + } + else if (_writeType == BatchedCommandRequest::BatchType_Update) { + for (size_t i = 0; i < numAttempts; ++i) { + globalOpCounters.gotUpdate(); + } + } + else if (_writeType == BatchedCommandRequest::BatchType_Delete) { + for (size_t i = 0; i < numAttempts; ++i) { + globalOpCounters.gotDelete(); + } + } - writer.write( request, &response ); + // Save the last opTimes written on each shard for this client, to allow GLE to work + if (ClientInfo::exists() && writer.getStats().hasShardStats()) { + ClientInfo* clientInfo = ClientInfo::get(NULL); + clientInfo->addHostOpTimes(writer.getStats().getShardStats().getWriteOpTimes()); } - dassert( response.isValid( NULL ) ); + // TODO + // There's a pending issue about how to report response here. If we use + // the command infra-structure, we should reuse the 'errmsg' field. But + // we have already filed that message inside the BatchCommandResponse. + // return response.getOk(); + result.appendElements(response.toBSON()); + return true; } - if ( cmdLastError ) { - // Populate the lastError object based on the write response - cmdLastError->reset(); - batchErrorToLastError( request, response, cmdLastError ); - } + protected: + /** + * Instantiates a command that can be invoked by "name", which will be capable of issuing + * write batches of type "writeType", and will require privilege "action" to run. + */ + ClusterWriteCmd(StringData name, BatchedCommandRequest::BatchType writeType) + : Command(name), + _writeType(writeType) { - size_t numAttempts; - if ( !response.getOk() ) { - numAttempts = 0; - } else if ( request.getOrdered() && response.isErrDetailsSet() ) { - numAttempts = response.getErrDetailsAt(0)->getIndex() + 1; // Add one failed attempt - } else { - numAttempts = request.sizeWriteOps(); } - // TODO: increase opcounters by more than one - if ( _writeType == BatchedCommandRequest::BatchType_Insert ) { - for( size_t i = 0; i < numAttempts; ++i ) { - globalOpCounters.gotInsert(); - } - } else if ( _writeType == BatchedCommandRequest::BatchType_Update ) { - for( size_t i = 0; i < numAttempts; ++i ) { - globalOpCounters.gotUpdate(); - } - } else if ( _writeType == BatchedCommandRequest::BatchType_Delete ) { - for( size_t i = 0; i < numAttempts; ++i ) { - globalOpCounters.gotDelete(); - } - } + private: + // Type of batch (e.g. insert, update). + const BatchedCommandRequest::BatchType _writeType; + }; - // Save the last opTimes written on each shard for this client, to allow GLE to work - if ( ClientInfo::exists() && writer.getStats().hasShardStats() ) { - ClientInfo* clientInfo = ClientInfo::get( NULL ); - clientInfo->addHostOpTimes( writer.getStats().getShardStats().getWriteOpTimes() ); - } - // TODO - // There's a pending issue about how to report response here. If we use - // the command infra-structure, we should reuse the 'errmsg' field. But - // we have already filed that message inside the BatchCommandResponse. - // return response.getOk(); - result.appendElements( response.toBSON() ); - return true; - } - - Status ClusterWriteCmd::explain(OperationContext* txn, - const std::string& dbname, - const BSONObj& cmdObj, - ExplainCommon::Verbosity verbosity, - BSONObjBuilder* out) const { - - BatchedCommandRequest request(_writeType); - - string errMsg; - if (!request.parseBSON(cmdObj, &errMsg) || !request.isValid(&errMsg)) { - return Status(ErrorCodes::FailedToParse, errMsg); - } + class ClusterCmdInsert : public ClusterWriteCmd { + public: + ClusterCmdInsert() : ClusterWriteCmd("insert", BatchedCommandRequest::BatchType_Insert) { - // Fixup the namespace to be a full ns internally - NamespaceString nss(dbname, request.getNS()); - request.setNS(nss.ns()); + } - // We can only explain write batches of size 1. - if (request.sizeWriteOps() != 1U) { - return Status(ErrorCodes::InvalidLength, "explained write batches must be of size 1"); + void help(stringstream& help) const { + help << "insert documents"; } - BSONObjBuilder explainCmdBob; - ClusterExplain::wrapAsExplain(cmdObj, verbosity, &explainCmdBob); + } clusterInsertCmd; - // We will time how long it takes to run the commands on the shards. - Timer timer; + class ClusterCmdUpdate : public ClusterWriteCmd { + public: + ClusterCmdUpdate() : ClusterWriteCmd("update", BatchedCommandRequest::BatchType_Update) { - // Target the command to the shards based on the singleton batch item. - BatchItemRef targetingBatchItem(&request, 0); - vector<Strategy::CommandResult> shardResults; - Status status = STRATEGY->commandOpWrite(dbname, - explainCmdBob.obj(), - targetingBatchItem, - &shardResults); - if (!status.isOK()) - return status; + } - long long millisElapsed = timer.millis(); + void help( stringstream& help ) const { + help << "update documents"; + } - return ClusterExplain::buildExplainResult(shardResults, - ClusterExplain::kWriteOnShards, - millisElapsed, - out); - } + } clusterUpdateCmd; - // - // Register write commands at startup - // + class ClusterCmdDelete : public ClusterWriteCmd { + public: + ClusterCmdDelete() : ClusterWriteCmd("delete", BatchedCommandRequest::BatchType_Delete) { - namespace { + } - MONGO_INITIALIZER(RegisterWriteCommands)(InitializerContext* context) { - // Leaked intentionally: a Command registers itself when constructed. - new ClusterCmdInsert(); - new ClusterCmdUpdate(); - new ClusterCmdDelete(); - return Status::OK(); + void help(stringstream& help) const { + help << "delete documents"; } - } // namespace + } clusterDeleteCmd; +} // namespace } // namespace mongo diff --git a/src/mongo/s/commands_admin.cpp b/src/mongo/s/commands_admin.cpp deleted file mode 100644 index ff1c0de862e..00000000000 --- a/src/mongo/s/commands_admin.cpp +++ /dev/null @@ -1,487 +0,0 @@ -/** -* Copyright (C) 2008 10gen Inc. -* -* This program is free software: you can redistribute it and/or modify -* it under the terms of the GNU Affero General Public License, version 3, -* as published by the Free Software Foundation. -* -* 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 -* GNU Affero General Public License for more details. -* -* You should have received a copy of the GNU Affero General Public License -* along with this program. If not, see <http://www.gnu.org/licenses/>. -* -* 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 GNU Affero General 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_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kCommand - -#include "mongo/platform/basic.h" - -#include "mongo/db/commands.h" - -#include <boost/scoped_ptr.hpp> -#include <boost/shared_ptr.hpp> - -#include "mongo/client/connpool.h" -#include "mongo/client/dbclientcursor.h" -#include "mongo/client/replica_set_monitor.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_manager.h" -#include "mongo/db/auth/authorization_session.h" -#include "mongo/db/auth/privilege.h" -#include "mongo/db/dbmessage.h" -#include "mongo/db/field_parser.h" -#include "mongo/db/hasher.h" -#include "mongo/db/index_names.h" -#include "mongo/db/query/lite_parsed_query.h" -#include "mongo/db/lasterror.h" -#include "mongo/db/stats/counters.h" -#include "mongo/db/wire_version.h" -#include "mongo/db/write_concern.h" -#include "mongo/db/write_concern_options.h" -#include "mongo/s/chunk_manager.h" -#include "mongo/s/client_info.h" -#include "mongo/s/client/shard_connection.h" -#include "mongo/s/cluster_write.h" -#include "mongo/s/config.h" -#include "mongo/s/dbclient_multi_command.h" -#include "mongo/s/dbclient_shard_resolver.h" -#include "mongo/s/distlock.h" -#include "mongo/s/grid.h" -#include "mongo/s/strategy.h" -#include "mongo/s/type_chunk.h" -#include "mongo/s/type_database.h" -#include "mongo/s/type_shard.h" -#include "mongo/s/write_ops/batch_downconvert.h" -#include "mongo/s/write_ops/batch_write_exec.h" -#include "mongo/s/write_ops/batched_command_request.h" -#include "mongo/util/log.h" -#include "mongo/util/net/listen.h" -#include "mongo/util/net/message.h" -#include "mongo/util/print.h" -#include "mongo/util/processinfo.h" -#include "mongo/util/ramlog.h" -#include "mongo/util/stringutils.h" -#include "mongo/util/timer.h" -#include "mongo/util/version.h" - -namespace mongo { - - using boost::scoped_ptr; - using boost::shared_ptr; - using std::auto_ptr; - using std::endl; - using std::list; - using std::map; - using std::set; - using std::string; - using std::stringstream; - using std::vector; - - namespace dbgrid_cmds { - - class GridAdminCmd : public Command { - public: - GridAdminCmd( const char * n ) : Command( n , false, tolowerString(n).c_str() ) { - - } - - virtual bool slaveOk() const { - return true; - } - - virtual bool adminOnly() const { - return true; - } - - virtual bool isWriteCommandForConfigServer() const { - return false; - } - }; - - // ------------ server level commands ------------- - - class ListShardsCmd : public GridAdminCmd { - public: - ListShardsCmd() : GridAdminCmd("listShards") { } - virtual void help( stringstream& help ) const { - help << "list all shards of the system"; - } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - ActionSet actions; - actions.addAction(ActionType::listShards); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); - } - bool run(OperationContext* txn, const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { - ScopedDbConnection conn(configServer.getPrimary().getConnString(), 30); - - vector<BSONObj> all; - auto_ptr<DBClientCursor> cursor = conn->query( ShardType::ConfigNS , BSONObj() ); - while ( cursor->more() ) { - BSONObj o = cursor->next(); - all.push_back( o ); - } - - result.append("shards" , all ); - conn.done(); - - return true; - } - } listShardsCmd; - - /* a shard is a single mongod server or a replica pair. add it (them) to the cluster as a storage partition. */ - class AddShard : public GridAdminCmd { - public: - AddShard() : GridAdminCmd("addShard") { } - virtual void help( stringstream& help ) const { - help << "add a new shard to the system"; - } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - ActionSet actions; - actions.addAction(ActionType::addShard); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); - } - bool run(OperationContext* txn, const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { - errmsg.clear(); - - // get replica set component hosts - ConnectionString servers = ConnectionString::parse( cmdObj.firstElement().valuestrsafe() , errmsg ); - if ( ! errmsg.empty() ) { - log() << "addshard request " << cmdObj << " failed:" << errmsg << endl; - return false; - } - - // using localhost in server names implies every other process must use localhost addresses too - vector<HostAndPort> serverAddrs = servers.getServers(); - for ( size_t i = 0 ; i < serverAddrs.size() ; i++ ) { - if ( serverAddrs[i].isLocalHost() != grid.allowLocalHost() ) { - errmsg = str::stream() << - "can't use localhost as a shard since all shards need to communicate. " << - "either use all shards and configdbs in localhost or all in actual IPs " << - " host: " << serverAddrs[i].toString() << " isLocalHost:" << serverAddrs[i].isLocalHost(); - - log() << "addshard request " << cmdObj << " failed: attempt to mix localhosts and IPs" << endl; - return false; - } - - // it's fine if mongods of a set all use default port - if ( ! serverAddrs[i].hasPort() ) { - serverAddrs[i] = HostAndPort(serverAddrs[i].host(), - ServerGlobalParams::ShardServerPort); - } - } - - // name is optional; addShard will provide one if needed - string name = ""; - if ( cmdObj["name"].type() == String ) { - name = cmdObj["name"].valuestrsafe(); - } - - // maxSize is the space usage cap in a shard in MBs - long long maxSize = 0; - if ( cmdObj[ ShardType::maxSize() ].isNumber() ) { - maxSize = cmdObj[ ShardType::maxSize() ].numberLong(); - } - - audit::logAddShard(ClientBasic::getCurrent(), name, servers.toString(), maxSize); - if ( ! grid.addShard( &name , servers , maxSize , errmsg ) ) { - log() << "addshard request " << cmdObj << " failed: " << errmsg << endl; - return false; - } - - result << "shardAdded" << name; - return true; - } - - } addServer; - - /* See usage docs at: - * http://dochub.mongodb.org/core/configuringsharding#ConfiguringSharding-Removingashard - */ - class RemoveShardCmd : public GridAdminCmd { - public: - RemoveShardCmd() : GridAdminCmd("removeShard") { } - virtual void help( stringstream& help ) const { - help << "remove a shard to the system."; - } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) { - ActionSet actions; - actions.addAction(ActionType::removeShard); - out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); - } - bool run(OperationContext* txn, const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { - string target = cmdObj.firstElement().valuestrsafe(); - Shard s = Shard::make( target ); - if ( ! grid.knowAboutShard( s.getConnString() ) ) { - errmsg = "unknown shard"; - return false; - } - - ScopedDbConnection conn(configServer.getPrimary().getConnString(), 30); - - if (conn->count(ShardType::ConfigNS, - BSON(ShardType::name() << NE << s.getName() << - ShardType::draining(true)))){ - conn.done(); - errmsg = "Can't have more than one draining shard at a time"; - return false; - } - - if (conn->count(ShardType::ConfigNS, BSON(ShardType::name() << NE << s.getName())) == 0){ - conn.done(); - errmsg = "Can't remove last shard"; - return false; - } - - BSONObj primaryDoc = BSON(DatabaseType::name.ne("local") << - DatabaseType::primary(s.getName())); - BSONObj dbInfo; // appended at end of result on success - { - boost::scoped_ptr<DBClientCursor> cursor (conn->query(DatabaseType::ConfigNS, primaryDoc)); - if (cursor->more()) { // skip block and allocations if empty - BSONObjBuilder dbInfoBuilder; - dbInfoBuilder.append("note", "you need to drop or movePrimary these databases"); - BSONArrayBuilder dbs(dbInfoBuilder.subarrayStart("dbsToMove")); - - while (cursor->more()){ - BSONObj db = cursor->nextSafe(); - dbs.append(db[DatabaseType::name()]); - } - dbs.doneFast(); - - dbInfo = dbInfoBuilder.obj(); - } - } - - // If the server is not yet draining chunks, put it in draining mode. - BSONObj searchDoc = BSON(ShardType::name() << s.getName()); - BSONObj drainingDoc = BSON(ShardType::name() << s.getName() << ShardType::draining(true)); - BSONObj shardDoc = conn->findOne(ShardType::ConfigNS, drainingDoc); - if ( shardDoc.isEmpty() ) { - - // TODO prevent move chunks to this shard. - - log() << "going to start draining shard: " << s.getName() << endl; - BSONObj newStatus = BSON( "$set" << BSON( ShardType::draining(true) ) ); - - Status status = clusterUpdate( ShardType::ConfigNS, - searchDoc, - newStatus, - false /* do no upsert */, - false /* multi */, - NULL ); - - if ( !status.isOK() ) { - errmsg = status.reason(); - log() << "error starting remove shard: " << s.getName() - << " err: " << errmsg << endl; - return false; - } - - BSONObj primaryLocalDoc = BSON(DatabaseType::name("local") << - DatabaseType::primary(s.getName())); - PRINT(primaryLocalDoc); - if (conn->count(DatabaseType::ConfigNS, primaryLocalDoc)) { - log() << "This shard is listed as primary of local db. Removing entry." << endl; - Status status = clusterDelete( DatabaseType::ConfigNS, - BSON(DatabaseType::name("local")), - 0 /* limit */, - NULL ); - - if ( !status.isOK() ) { - log() << "error removing local db: " - << status.reason() << endl; - return false; - } - } - - Shard::reloadShardInfo(); - - result.append( "msg" , "draining started successfully" ); - result.append( "state" , "started" ); - result.append( "shard" , s.getName() ); - result.appendElements(dbInfo); - conn.done(); - - // Record start in changelog - configServer.logChange( "removeShard.start", - "", - buildRemoveLogEntry( s, true ) ); - - return true; - } - - // If the server has been completely drained, remove it from the ConfigDB. - // Check not only for chunks but also databases. - BSONObj shardIDDoc = BSON(ChunkType::shard(shardDoc[ShardType::name()].str())); - long long chunkCount = conn->count(ChunkType::ConfigNS, shardIDDoc); - long long dbCount = conn->count( DatabaseType::ConfigNS , primaryDoc ); - if ( ( chunkCount == 0 ) && ( dbCount == 0 ) ) { - log() << "going to remove shard: " << s.getName() << endl; - audit::logRemoveShard(ClientBasic::getCurrent(), s.getName()); - Status status = clusterDelete( ShardType::ConfigNS, - searchDoc, - 0, // limit - NULL ); - - if ( !status.isOK() ) { - errmsg = status.reason(); - log() << "error concluding remove shard: " << s.getName() - << " err: " << errmsg << endl; - return false; - } - - string shardName = shardDoc[ ShardType::name() ].str(); - Shard::removeShard( shardName ); - shardConnectionPool.removeHost( shardName ); - ReplicaSetMonitor::remove( shardName, true ); - Shard::reloadShardInfo(); - - result.append( "msg" , "removeshard completed successfully" ); - result.append( "state" , "completed" ); - result.append( "shard" , s.getName() ); - conn.done(); - - // Record finish in changelog - configServer.logChange( "removeShard", "", buildRemoveLogEntry( s, false ) ); - - return true; - } - - // If the server is already in draining mode, just report on its progress. - // Report on databases (not just chunks) that are left too. - result.append( "msg" , "draining ongoing" ); - result.append( "state" , "ongoing" ); - BSONObjBuilder inner; - inner.append( "chunks" , chunkCount ); - inner.append( "dbs" , dbCount ); - result.append( "remaining" , inner.obj() ); - result.appendElements(dbInfo); - - conn.done(); - return true; - } - private: - BSONObj buildRemoveLogEntry( Shard s, const bool isDraining ) { - BSONObjBuilder details; - details.append("shard", s.getName()); - details.append("isDraining", isDraining); - - return details.obj(); - } - } removeShardCmd; - - - // --------------- public commands ---------------- - - class IsDbGridCmd : public Command { - public: - virtual bool isWriteCommandForConfigServer() const { return false; } - virtual bool slaveOk() const { - return true; - } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) {} // No auth required - IsDbGridCmd() : Command("isdbgrid") { } - bool run(OperationContext* txn, const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { - result.append("isdbgrid", 1); - result.append("hostname", getHostNameCached()); - return true; - } - } isdbgrid; - - class CmdIsMaster : public Command { - public: - virtual bool isWriteCommandForConfigServer() const { return false; } - virtual bool slaveOk() const { - return true; - } - virtual void help( stringstream& help ) const { - help << "test if this is master half of a replica pair"; - } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) {} // No auth required - CmdIsMaster() : Command("isMaster" , false , "ismaster") { } - virtual bool run(OperationContext* txn, const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { - result.appendBool("ismaster", true ); - result.append("msg", "isdbgrid"); - result.appendNumber("maxBsonObjectSize", BSONObjMaxUserSize); - result.appendNumber("maxMessageSizeBytes", MaxMessageSizeBytes); - result.appendNumber("maxWriteBatchSize", - BatchedCommandRequest::kMaxWriteBatchSize); - result.appendDate("localTime", jsTime()); - - // Mongos tries to keep exactly the same version range of the server it is - // compiled for. - result.append("maxWireVersion", maxWireVersion); - result.append("minWireVersion", minWireVersion); - - return true; - } - } ismaster; - - class CmdWhatsMyUri : public Command { - public: - CmdWhatsMyUri() : Command("whatsmyuri") { } - virtual bool slaveOk() const { - return true; - } - virtual bool isWriteCommandForConfigServer() const { return false; } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) {} // No auth required - virtual void help( stringstream &help ) const { - help << "{whatsmyuri:1}"; - } - virtual bool run(OperationContext* txn, const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { - result << "you" << ClientInfo::get()->getRemote().toString(); - return true; - } - } cmdWhatsMyUri; - - - class CmdShardingGetPrevError : public Command { - public: - virtual bool isWriteCommandForConfigServer() const { return false; } - virtual bool slaveOk() const { - return true; - } - virtual void help( stringstream& help ) const { - help << "get previous error (since last reseterror command)"; - } - virtual void addRequiredPrivileges(const std::string& dbname, - const BSONObj& cmdObj, - std::vector<Privilege>* out) {} // No auth required - CmdShardingGetPrevError() : Command( "getPrevError" , false , "getpreverror") { } - virtual bool run(OperationContext* txn, const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { - errmsg += "getpreverror not supported for sharded environments"; - return false; - } - } cmdGetPrevError; - - } - -} // namespace mongo |