示例#1
0
BSONObj ShardIdentityType::toBSON() const {
    BSONObjBuilder builder;

    builder.append("_id", IdName);

    if (_configsvrConnString) {
        builder << configsvrConnString(_configsvrConnString->toString());
    }

    if (_shardName) {
        builder << shardName(_shardName.get());
    }

    if (_clusterId) {
        builder << clusterId(_clusterId.get());
    }

    return builder.obj();
}
示例#2
0
Status ShardIdentityType::validate() const {
    if (!_configsvrConnString) {
        return {ErrorCodes::NoSuchKey,
                str::stream() << "missing " << configsvrConnString() << " field"};
    }

    if (_configsvrConnString->type() != ConnectionString::SET) {
        return {ErrorCodes::UnsupportedFormat,
                str::stream() << "config connection string can only be replica sets, got "
                << ConnectionString::typeToString(_configsvrConnString->type())};
    }

    if (!_shardName || _shardName->empty()) {
        return {ErrorCodes::NoSuchKey, str::stream() << "missing " << shardName() << " field"};
    }

    if (!_clusterId || !_clusterId->isSet()) {
        return {ErrorCodes::NoSuchKey, str::stream() << "missing " << clusterId() << " field"};
    }

    return Status::OK();
}
示例#3
0
StatusWith<ShardIdentityType> ShardIdentityType::fromBSON(const BSONObj& source) {
    if (!source.hasField("_id")) {
        return {ErrorCodes::NoSuchKey,
                str::stream() << "missing _id field for shardIdentity document"};
    }

    ShardIdentityType shardIdentity;

    {
        std::string docId;
        Status status = bsonExtractStringField(source, "_id", &docId);
        if (!status.isOK()) {
            return status;
        }

        if (docId != IdName) {
            return {ErrorCodes::FailedToParse,
                    str::stream() << "got _id: " << docId << " instead of " << IdName};
        }
    }

    {
        std::string connString;
        Status status = bsonExtractStringField(source, configsvrConnString(), &connString);
        if (!status.isOK()) {
            return status;
        }

        try {
            // Note: ConnectionString::parse can uassert from HostAndPort constructor.
            auto parsedConfigConnStrStatus = ConnectionString::parse(connString);
            if (!parsedConfigConnStrStatus.isOK()) {
                return parsedConfigConnStrStatus.getStatus();
            }

            auto configSvrConnStr = parsedConfigConnStrStatus.getValue();
            if (configSvrConnStr.type() != ConnectionString::SET) {
                return Status(ErrorCodes::UnsupportedFormat,
                              str::stream()
                              << "config server connection string can only be replica sets: "
                              << configSvrConnStr.toString());
            }

            shardIdentity.setConfigsvrConnString(std::move(configSvrConnStr));
        } catch (const UserException& parseException) {
            return parseException.toStatus();
        }
    }

    {
        std::string name;
        Status status = bsonExtractStringField(source, shardName(), &name);
        if (!status.isOK()) {
            return status;
        }

        shardIdentity.setShardName(name);
    }

    {
        OID oid;
        Status status = bsonExtractOIDField(source, clusterId(), &oid);
        if (!status.isOK()) {
            return status;
        }

        shardIdentity.setClusterId(oid);
    }

    return shardIdentity;
}
示例#4
0
    StatusWith<string> isValidShard(const string& name,
                                    const ConnectionString& shardConnectionString,
                                    ScopedDbConnection& conn) {
        if (conn->type() == ConnectionString::SYNC) {
            return Status(ErrorCodes::BadValue,
                          "can't use sync cluster as a shard; for a replica set, "
                          "you have to use <setname>/<server1>,<server2>,...");
        }

        BSONObj resIsMongos;
        // (ok == 0) implies that it is a mongos
        if (conn->runCommand("admin", BSON("isdbgrid" << 1), resIsMongos)) {
            return Status(ErrorCodes::BadValue,
                          "can't add a mongos process as a shard");
        }

        BSONObj resIsMaster;
        if (!conn->runCommand("admin", BSON("isMaster" << 1), resIsMaster)) {
            return Status(ErrorCodes::OperationFailed,
                          str::stream() << "failed running isMaster: " << resIsMaster);
        }

        // if the shard has only one host, make sure it is not part of a replica set
        string setName = resIsMaster["setName"].str();
        string commandSetName = shardConnectionString.getSetName();
        if (commandSetName.empty() && !setName.empty()) {
            return Status(ErrorCodes::BadValue,
                          str::stream() << "host is part of set " << setName << "; "
                                        << "use replica set url format "
                                        << "<setname>/<server1>,<server2>, ...");
        }

        if (!commandSetName.empty() && setName.empty()) {
            return Status(ErrorCodes::OperationFailed,
                          str::stream() << "host did not return a set name; "
                                        << "is the replica set still initializing? "
                                        << resIsMaster);
        }

        // if the shard is part of replica set, make sure it is the right one
        if (!commandSetName.empty() && (commandSetName != setName)) {
            return Status(ErrorCodes::OperationFailed,
                          str::stream() << "host is part of a different set: " << setName);
        }

        if (setName.empty()) {
            // check this isn't a --configsvr
            BSONObj res;
            bool ok = conn->runCommand("admin",
                                       BSON("replSetGetStatus" << 1),
                                       res);
            if(!ok && res["info"].type() == String && res["info"].String() == "configsvr") {
                return Status(ErrorCodes::BadValue,
                              "the specified mongod is a --configsvr and "
                              "should thus not be a shard server");
            }
        }

        // if the shard is part of a replica set,
        // make sure all the hosts mentioned in 'shardConnectionString' are part of
        // the set. It is fine if not all members of the set are present in 'shardConnectionString'.
        bool foundAll = true;
        string offendingHost;
        if (!commandSetName.empty()) {
            set<string> hostSet;
            BSONObjIterator iter(resIsMaster["hosts"].Obj());
            while (iter.more()) {
                hostSet.insert(iter.next().String()); // host:port
            }
            if (resIsMaster["passives"].isABSONObj()) {
                BSONObjIterator piter(resIsMaster["passives"].Obj());
                while (piter.more()) {
                    hostSet.insert(piter.next().String()); // host:port
                }
            }
            if (resIsMaster["arbiters"].isABSONObj()) {
                BSONObjIterator piter(resIsMaster["arbiters"].Obj());
                while (piter.more()) {
                    hostSet.insert(piter.next().String()); // host:port
                }
            }

            vector<HostAndPort> hosts = shardConnectionString.getServers();
            for (size_t i = 0; i < hosts.size(); i++) {
                if (!hosts[i].hasPort()) {
                    hosts[i] = HostAndPort(hosts[i].host(), hosts[i].port());
                }
                string host = hosts[i].toString(); // host:port
                if (hostSet.find(host) == hostSet.end()) {
                    offendingHost = host;
                    foundAll = false;
                    break;
                }
            }
        }
        if (!foundAll) {
            return Status(ErrorCodes::OperationFailed,
                          str::stream() << "in seed list " << shardConnectionString.toString()
                                        << ", host " << offendingHost
                                        << " does not belong to replica set " << setName);
        }

        string shardName(name);
        // shard name defaults to the name of the replica set
        if (name.empty() && !setName.empty()) {
            shardName = setName;
        }

        // disallow adding shard replica set with name 'config'
        if (shardName == "config") {
            return Status(ErrorCodes::BadValue,
                          "use of shard replica set with name 'config' is not allowed");
        }

        return shardName;
    }