void ReplSetConfig::MemberCfg::check() const { mchk(_id >= 0 && _id <= 255); mchk(priority >= 0 && priority <= 1000); mchk(votes >= 0 && votes <= 100); uassert(13419, "this version of mongod only supports priorities 0 and 1", priority == 0 || priority == 1); uassert(13437, "slaveDelay requires priority be zero", slaveDelay == 0 || priority == 0); uassert(13438, "bad slaveDelay value", slaveDelay >= 0 && slaveDelay <= 3600 * 24 * 366); uassert(13439, "priority must be 0 when hidden=true", priority == 0 || !hidden); uassert(13477, "priority must be 0 when buildIndexes=false", buildIndexes || priority == 0); if (!initialSync.isEmpty()) { static const string legal[] = {"state", "name", "_id","optime"}; static const set<string> legals(legal, legal + 4); assertOnlyHas(initialSync, legals); if (initialSync.hasElement("state")) { uassert(13525, "initialSync source state must be 1 or 2", initialSync["state"].isNumber() && (initialSync["state"].Number() == 1 || initialSync["state"].Number() == 2)); } if (initialSync.hasElement("name")) { uassert(13526, "initialSync source name must be a string", initialSync["name"].type() == mongo::String); } if (initialSync.hasElement("_id")) { uassert(13527, "initialSync source _id must be a number", initialSync["_id"].isNumber()); } if (initialSync.hasElement("optime")) { uassert(13528, "initialSync source optime must be a timestamp", initialSync["optime"].type() == mongo::Timestamp || initialSync["optime"].type() == mongo::Date); } } }
void ReplSetConfig::from(BSONObj o) { static const string legal[] = {"_id","version", "members","settings"}; static const set<string> legals(legal, legal + 4); assertOnlyHas(o, legals); md5 = o.md5(); _id = o["_id"].String(); if( o["version"].ok() ) { version = o["version"].numberInt(); uassert(13115, "bad " + rsConfigNs + " config: version", version > 0); } if( o["settings"].ok() ) { BSONObj settings = o["settings"].Obj(); if( settings["heartbeatConnRetries "].ok() ) ho.heartbeatConnRetries = settings["heartbeatConnRetries "].numberInt(); if( settings["heartbeatSleep"].ok() ) ho.heartbeatSleepMillis = (unsigned) (settings["heartbeatSleep"].Number() * 1000); if( settings["heartbeatTimeout"].ok() ) ho.heartbeatTimeoutMillis = (unsigned) (settings["heartbeatTimeout"].Number() * 1000); ho.check(); try { getLastErrorDefaults = settings["getLastErrorDefaults"].Obj().copy(); } catch(...) { } } set<string> hosts; set<int> ords; vector<BSONElement> members; try { members = o["members"].Array(); } catch(...) { uasserted(13131, "replSet error parsing (or missing) 'members' field in config object"); } unsigned localhosts = 0; for( unsigned i = 0; i < members.size(); i++ ) { BSONObj mobj = members[i].Obj(); MemberCfg m; try { static const string legal[] = { "_id","votes","priority","host", "hidden","slaveDelay", "arbiterOnly","buildIndexes","tags","initialSync" // deprecated }; static const set<string> legals(legal, legal + 10); assertOnlyHas(mobj, legals); try { m._id = (int) mobj["_id"].Number(); } catch(...) { /* TODO: use of string exceptions may be problematic for reconfig case! */ throw "_id must be numeric"; } string s; try { s = mobj["host"].String(); m.h = HostAndPort(s); } catch(...) { throw string("bad or missing host field? ") + mobj.toString(); } if( m.h.isLocalHost() ) localhosts++; m.arbiterOnly = mobj["arbiterOnly"].trueValue(); m.slaveDelay = mobj["slaveDelay"].numberInt(); if( mobj.hasElement("hidden") ) m.hidden = mobj["hidden"].trueValue(); if( mobj.hasElement("buildIndexes") ) m.buildIndexes = mobj["buildIndexes"].trueValue(); if( mobj.hasElement("priority") ) m.priority = mobj["priority"].Number(); if( mobj.hasElement("votes") ) m.votes = (unsigned) mobj["votes"].Number(); if( mobj.hasElement("tags") ) { vector<BSONElement> v = mobj["tags"].Array(); for( unsigned i = 0; i < v.size(); i++ ) m.tags.insert( v[i].String() ); } m.check(); } catch( const char * p ) { log() << "replSet cfg parsing exception for members[" << i << "] " << p << rsLog; stringstream ss; ss << "replSet members[" << i << "] " << p; uassert(13107, ss.str(), false); } catch(DBException& e) { log() << "replSet cfg parsing exception for members[" << i << "] " << e.what() << rsLog; stringstream ss; ss << "bad config for member[" << i << "] " << e.what(); uassert(13135, ss.str(), false); } if( !(ords.count(m._id) == 0 && hosts.count(m.h.toString()) == 0) ) { log() << "replSet " << o.toString() << rsLog; uassert(13108, "bad replset config -- duplicate hosts in the config object?", false); } hosts.insert(m.h.toString()); ords.insert(m._id); this->members.push_back(m); } uassert(13393, "can't use localhost in repl set member names except when using it for all members", localhosts == 0 || localhosts == members.size()); uassert(13117, "bad " + rsConfigNs + " config", !_id.empty()); }