diff --git a/jstests/sharding/addshard2.js b/jstests/sharding/addshard2.js index d6487c6d366a3..dab39ec42400a 100644 --- a/jstests/sharding/addshard2.js +++ b/jstests/sharding/addshard2.js @@ -25,6 +25,15 @@ var rs4 = new ReplSetTest({ 'name': 'admin', nodes: 3, startPort: 31209 }); rs4.startSet(); rs4.initiate(); +// replica set with configServer: true should *not* be allowed to be added as a shard +var rs5 = new ReplSetTest({ 'name': 'csrs', nodes: 3, startPort: 31212 }); +rs5.startSet(); +var conf = rs5.getReplSetConfig(); +conf.configServer = true; +conf.settings = {protocolVersion: 1}; +rs5.initiate(conf); + + // step 1. name given assert(s.admin.runCommand({"addshard" : getHostName()+":" + conn1.port, "name" : "bar"}).ok, "failed to add shard in step 1"); @@ -82,8 +91,12 @@ var wRes = s.getDB('test').foo.insert({ x: 1 }); assert(!wRes.hasWriteError() && wRes.nInserted === 1, 'failed to insert document into "test.foo" unsharded collection'); +// SERVER-19545 Should not be able to add config server replsets as shards. +assert.commandFailed(s.admin.runCommand({addshard: rs5.getURL()})); + s.stop(); rs1.stopSet(); rs2.stopSet(); rs3.stopSet(); rs4.stopSet(); +rs5.stopSet(); \ No newline at end of file diff --git a/src/mongo/db/repl/topology_coordinator_impl.cpp b/src/mongo/db/repl/topology_coordinator_impl.cpp index 26433cc4f16c3..dec1362d2d04d 100644 --- a/src/mongo/db/repl/topology_coordinator_impl.cpp +++ b/src/mongo/db/repl/topology_coordinator_impl.cpp @@ -1503,6 +1503,10 @@ void TopologyCoordinatorImpl::prepareStatusResponse(const ReplicationExecutor::C response->append("syncingTo", _syncSource.toString()); } + if (_rsConfig.isConfigServer()) { + response->append("configServer", true); + } + response->append("members", membersOut); *result = Status::OK(); } diff --git a/src/mongo/s/catalog/catalog_manager.cpp b/src/mongo/s/catalog/catalog_manager.cpp index 2eb60e4551919..8b17a81149646 100644 --- a/src/mongo/s/catalog/catalog_manager.cpp +++ b/src/mongo/s/catalog/catalog_manager.cpp @@ -36,6 +36,7 @@ #include "mongo/base/status.h" #include "mongo/base/status_with.h" +#include "mongo/bson/util/bson_extract.h" #include "mongo/client/read_preference.h" #include "mongo/client/remote_command_targeter.h" #include "mongo/client/replica_set_monitor.h" @@ -182,20 +183,34 @@ StatusWith validateHostAsShard(ShardRegistry* shardRegistry, } // Is it a mongos config server? - if (foundSetName.empty()) { - cmdStatus = shardRegistry->runCommand(shardHost, "admin", BSON("replSetGetStatus" << 1)); - if (!cmdStatus.isOK()) { - return cmdStatus.getStatus(); - } + cmdStatus = shardRegistry->runCommand(shardHost, "admin", BSON("replSetGetStatus" << 1)); + if (!cmdStatus.isOK()) { + return cmdStatus.getStatus(); + } - BSONObj res = cmdStatus.getValue(); + BSONObj res = cmdStatus.getValue(); - if (!getStatusFromCommandResult(res).isOK() && (res["info"].type() == String) && - (res["info"].String() == "configsvr")) { + if (getStatusFromCommandResult(res).isOK()) { + bool isConfigServer; + Status status = + bsonExtractBooleanFieldWithDefault(res, "configServer", false, &isConfigServer); + if (!status.isOK()) { + return Status(status.code(), + str::stream() << "replSetGetStatus returned invalid \"configServer\" " + << "field when attempting to add " + << connectionString.toString() + << " as a shard: " << status.reason()); + } + + if (isConfigServer) { return {ErrorCodes::BadValue, - "the specified mongod is a legacy-style config " - "server and cannot be used as a shard server"}; + str::stream() << "Cannot add " << connectionString.toString() + << " as a shard since it is part of a config server replica set"}; } + } else if ((res["info"].type() == String) && (res["info"].String() == "configsvr")) { + return {ErrorCodes::BadValue, + "the specified mongod is a legacy-style config " + "server and cannot be used as a shard server"}; } // If the shard is part of a replica set, make sure all the hosts mentioned in the connection