Status ReplSetRequestVotesResponse::initialize(const BSONObj& argsObj) { Status status = bsonCheckOnlyHasFields("ReplSetRequestVotes", argsObj, kLegalResponseFieldNames); if (!status.isOK()) return status; status = bsonExtractIntegerField(argsObj, kTermFieldName, &_term); if (!status.isOK()) return status; status = bsonExtractBooleanField(argsObj, kVoteGrantedFieldName, &_voteGranted); if (!status.isOK()) return status; status = bsonExtractStringField(argsObj, kReasonFieldName, &_reason); if (!status.isOK()) return status; status = bsonExtractBooleanField(argsObj, kOkFieldName, &_ok); if (!status.isOK()) return status; return Status::OK(); }
StatusWith<MigrationSecondaryThrottleOptions> MigrationSecondaryThrottleOptions::createFromCommand( const BSONObj& obj) { SecondaryThrottleOption secondaryThrottle; boost::optional<BSONObj> writeConcernBSON; // Parse the two variants of the 'secondaryThrottle' option { bool isSecondaryThrottle; Status status = bsonExtractBooleanField(obj, kSecondaryThrottleMongod, &isSecondaryThrottle); if (status == ErrorCodes::NoSuchKey) { status = bsonExtractBooleanField(obj, kSecondaryThrottleMongos, &isSecondaryThrottle); } if (status == ErrorCodes::NoSuchKey) { secondaryThrottle = kDefault; } else if (status.isOK()) { secondaryThrottle = (isSecondaryThrottle ? kOn : kOff); } else { return status; } } // Extract the requested 'writeConcern' option { BSONElement writeConcernElem; Status status = bsonExtractField(obj, kWriteConcern, &writeConcernElem); if (status == ErrorCodes::NoSuchKey) { return MigrationSecondaryThrottleOptions(secondaryThrottle, boost::none); } else if (!status.isOK()) { return status; } if (secondaryThrottle != kOn) { return Status(ErrorCodes::UnsupportedFormat, "Cannot specify write concern when secondaryThrottle is not set"); } writeConcernBSON = writeConcernElem.Obj().getOwned(); } invariant(writeConcernBSON.is_initialized()); // Make sure the write concern parses correctly WriteConcernOptions writeConcern; Status status = writeConcern.parse(*writeConcernBSON); if (!status.isOK()) { return status; } return MigrationSecondaryThrottleOptions(secondaryThrottle, std::move(writeConcernBSON)); }
Status _extractRoleDataFromBSONArray(const BSONElement& rolesElement, const std::string& dbname, std::vector<User::RoleData> *parsedRoleData) { for (BSONObjIterator it(rolesElement.Obj()); it.more(); it.next()) { BSONElement element = *it; if (element.type() == String) { RoleName roleName(element.String(), dbname); parsedRoleData->push_back(User::RoleData(roleName, true, false)); } else if (element.type() == Object) { // Check that the role object is valid V2UserDocumentParser parser; BSONObj roleObj = element.Obj(); Status status = parser.checkValidRoleObject(roleObj, true); if (!status.isOK()) { return status; } std::string roleName; std::string roleSource; bool hasRole; bool canDelegate; status = bsonExtractStringField(roleObj, "name", &roleName); if (!status.isOK()) { return status; } status = bsonExtractStringField(roleObj, "source", &roleSource); if (!status.isOK()) { return status; } status = bsonExtractBooleanField(roleObj, "hasRole", &hasRole); if (!status.isOK()) { return status; } status = bsonExtractBooleanField(roleObj, "canDelegate", &canDelegate); if (!status.isOK()) { return status; } parsedRoleData->push_back(User::RoleData(RoleName(roleName, roleSource), hasRole, canDelegate)); } else { return Status(ErrorCodes::UnsupportedFormat, "Values in 'roles' array must be sub-documents or strings"); } } return Status::OK(); }
StatusWith<MigrationSecondaryThrottleOptions> MigrationSecondaryThrottleOptions::createFromBalancerConfig(const BSONObj& obj) { { bool isSecondaryThrottle; Status status = bsonExtractBooleanField(obj, kSecondaryThrottleMongos, &isSecondaryThrottle); if (status.isOK()) { return MigrationSecondaryThrottleOptions::create(isSecondaryThrottle ? kOn : kOff); } else if (status == ErrorCodes::NoSuchKey) { return MigrationSecondaryThrottleOptions::create(kDefault); } else if (status != ErrorCodes::TypeMismatch) { return status; } } // Try to load it as a BSON document BSONElement elem; Status status = bsonExtractTypedField(obj, kSecondaryThrottleMongos, BSONType::Object, &elem); WriteConcernOptions writeConcern; Status writeConcernParseStatus = writeConcern.parse(elem.Obj()); if (!writeConcernParseStatus.isOK()) { return writeConcernParseStatus; } return MigrationSecondaryThrottleOptions::createWithWriteConcern(writeConcern); }
Status ReplSetRequestVotesArgs::initialize(const BSONObj& argsObj) { Status status = bsonCheckOnlyHasFields("ReplSetRequestVotes", argsObj, kLegalArgsFieldNames); if (!status.isOK()) return status; status = bsonExtractIntegerField(argsObj, kTermFieldName, &_term); if (!status.isOK()) return status; status = bsonExtractIntegerField(argsObj, kCandidateIdFieldName, &_candidateId); if (!status.isOK()) return status; status = bsonExtractIntegerField(argsObj, kConfigVersionFieldName, &_cfgver); if (!status.isOK()) return status; status = bsonExtractStringField(argsObj, kSetNameFieldName, &_setName); if (!status.isOK()) return status; status = bsonExtractBooleanField(argsObj, kDryRunFieldName, &_dryRun); if (!status.isOK()) return status; status = bsonExtractOpTimeField(argsObj, kLastCommittedOpFieldName, &_lastCommittedOp); if (!status.isOK()) return status; return Status::OK(); }
StatusWith<ChunkType> ChunkType::fromBSON(const BSONObj& source) { ChunkType chunk; { std::string chunkName; Status status = bsonExtractStringField(source, name.name(), &chunkName); if (!status.isOK()) return status; chunk._name = chunkName; } { std::string chunkNS; Status status = bsonExtractStringField(source, ns.name(), &chunkNS); if (!status.isOK()) return status; chunk._ns = chunkNS; } { auto chunkRangeStatus = ChunkRange::fromBSON(source); if (!chunkRangeStatus.isOK()) return chunkRangeStatus.getStatus(); const auto chunkRange = std::move(chunkRangeStatus.getValue()); chunk._min = chunkRange.getMin().getOwned(); chunk._max = chunkRange.getMax().getOwned(); } { std::string chunkShard; Status status = bsonExtractStringField(source, shard.name(), &chunkShard); if (!status.isOK()) return status; chunk._shard = chunkShard; } { bool chunkJumbo; Status status = bsonExtractBooleanField(source, jumbo.name(), &chunkJumbo); if (status.isOK()) { chunk._jumbo = chunkJumbo; } else if (status == ErrorCodes::NoSuchKey) { // Jumbo status is missing, so it will be presumed false } else { return status; } } // The format of chunk version encoding is { lastmod: <Major|Minor>, lastmodEpoch: OID } if (!ChunkVersion::canParseBSON(source, DEPRECATED_lastmod())) { return Status(ErrorCodes::BadValue, str::stream() << "Unable to parse chunk version from " << source); } chunk._version = ChunkVersion::fromBSON(source, DEPRECATED_lastmod()); return chunk; }
StatusWith<AutoSplitSettingsType> AutoSplitSettingsType::fromBSON(const BSONObj& obj) { bool shouldAutoSplit; Status status = bsonExtractBooleanField(obj, kEnabled, &shouldAutoSplit); if (!status.isOK()) return status; AutoSplitSettingsType settings; settings._shouldAutoSplit = shouldAutoSplit; return settings; }
StatusWith<MongosType> MongosType::fromBSON(const BSONObj& source) { MongosType mt; { std::string mtName; Status status = bsonExtractStringField(source, name.name(), &mtName); if (!status.isOK()) return status; mt._name = mtName; } { BSONElement mtPingElem; Status status = bsonExtractTypedField(source, ping.name(), BSONType::Date, &mtPingElem); if (!status.isOK()) return status; mt._ping = mtPingElem.date(); } { long long mtUptime; Status status = bsonExtractIntegerField(source, uptime.name(), &mtUptime); if (!status.isOK()) return status; mt._uptime = mtUptime; } { bool mtWaiting; Status status = bsonExtractBooleanField(source, waiting.name(), &mtWaiting); if (!status.isOK()) return status; mt._waiting = mtWaiting; } if (source.hasField(mongoVersion.name())) { std::string mtMongoVersion; Status status = bsonExtractStringField(source, mongoVersion.name(), &mtMongoVersion); if (!status.isOK()) return status; mt._mongoVersion = mtMongoVersion; } if (source.hasField(configVersion.name())) { long long mtConfigVersion; Status status = bsonExtractIntegerField(source, configVersion.name(), &mtConfigVersion); if (!status.isOK()) return status; mt._configVersion = mtConfigVersion; } return mt; }
StatusWith<ChunkType> ChunkType::fromConfigBSON(const BSONObj& source) { ChunkType chunk; { std::string chunkNS; Status status = bsonExtractStringField(source, ns.name(), &chunkNS); if (!status.isOK()) return status; chunk._nss = NamespaceString(chunkNS); } { auto chunkRangeStatus = ChunkRange::fromBSON(source); if (!chunkRangeStatus.isOK()) return chunkRangeStatus.getStatus(); const auto chunkRange = std::move(chunkRangeStatus.getValue()); chunk._min = chunkRange.getMin().getOwned(); chunk._max = chunkRange.getMax().getOwned(); } { std::string chunkShard; Status status = bsonExtractStringField(source, shard.name(), &chunkShard); if (!status.isOK()) return status; chunk._shard = chunkShard; } { bool chunkJumbo; Status status = bsonExtractBooleanField(source, jumbo.name(), &chunkJumbo); if (status.isOK()) { chunk._jumbo = chunkJumbo; } else if (status == ErrorCodes::NoSuchKey) { // Jumbo status is missing, so it will be presumed false } else { return status; } } { auto versionStatus = ChunkVersion::parseFromBSONForChunk(source); if (!versionStatus.isOK()) { return versionStatus.getStatus(); } chunk._version = std::move(versionStatus.getValue()); } return chunk; }
Status parseAndValidateInfoCommands(const BSONObj& cmdObj, const StringData& cmdName, const std::string& dbname, bool* parsedAnyDB, BSONElement* parsedNameFilter) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert("anyDB"); validFieldNames.insert("writeConcern"); validFieldNames.insert("details"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } if (cmdObj[cmdName].type() != String && cmdObj[cmdName].type() != RegEx) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Argument to \"" << cmdName << "\"command must be either a string or a regex"); } *parsedNameFilter = cmdObj[cmdName]; bool anyDB = false; if (cmdObj.hasField("anyDB")) { if (dbname == "admin") { Status status = bsonExtractBooleanField(cmdObj, "anyDB", &anyDB); if (!status.isOK()) { return status; } } else { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "\"anyDB\" argument to \"" << cmdName << "\"command is only valid when run on the \"admin\" database"); } } *parsedAnyDB = anyDB; return Status::OK(); }
Status parseAndValidateUsersInfoCommand(const BSONObj& cmdObj, const std::string& dbname, bool* parsedAnyDB, BSONElement* parsedUsersFilter) { unordered_set<std::string> validFieldNames; validFieldNames.insert("usersInfo"); validFieldNames.insert("anyDB"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "usersInfo", validFieldNames); if (!status.isOK()) { return status; } if (cmdObj["usersInfo"].type() != String && cmdObj["usersInfo"].type() != RegEx) { return Status(ErrorCodes::BadValue, "Argument to userInfo command must be either a string or a regex"); } *parsedUsersFilter = cmdObj["usersInfo"]; bool anyDB = false; if (cmdObj.hasField("anyDB")) { if (dbname == "admin") { Status status = bsonExtractBooleanField(cmdObj, "anyDB", &anyDB); if (!status.isOK()) { return status; } } else { return Status(ErrorCodes::BadValue, "\"anyDB\" argument to usersInfo command is only valid when " "run on the \"admin\" database"); } } *parsedAnyDB = anyDB; return Status::OK(); }
StatusWith<SettingsType> SettingsType::fromBSON(const BSONObj& source) { SettingsType settings; { std::string settingsKey; Status status = bsonExtractStringField(source, key.name(), &settingsKey); if (!status.isOK()) return status; settings._key = settingsKey; } if (settings._key == ChunkSizeDocKey) { long long settingsChunkSizeMB; Status status = bsonExtractIntegerField(source, chunkSizeMB.name(), &settingsChunkSizeMB); if (!status.isOK()) return status; settings._chunkSizeMB = settingsChunkSizeMB; } else if (settings._key == BalancerDocKey) { { bool settingsBalancerStopped; Status status = bsonExtractBooleanFieldWithDefault( source, balancerStopped.name(), false, &settingsBalancerStopped); if (!status.isOK()) return status; settings._balancerStopped = settingsBalancerStopped; } { BSONElement settingsBalancerActiveWindowElem; Status status = bsonExtractTypedField( source, balancerActiveWindow.name(), Object, &settingsBalancerActiveWindowElem); if (status != ErrorCodes::NoSuchKey) { if (!status.isOK()) return status; StatusWith<BoostTimePair> timePairResult = settings._parseBalancingWindow(settingsBalancerActiveWindowElem.Obj()); if (!timePairResult.isOK()) return timePairResult.getStatus(); settings._balancerActiveWindow = timePairResult.getValue(); } } { BSONElement settingsMigrationWriteConcernElem; Status status = bsonExtractTypedField( source, migrationWriteConcern.name(), Object, &settingsMigrationWriteConcernElem); if (status == ErrorCodes::TypeMismatch) { bool settingsSecondaryThrottle; status = bsonExtractBooleanFieldWithDefault( source, deprecated_secondaryThrottle.name(), true, &settingsSecondaryThrottle); if (!status.isOK()) return status; settings._secondaryThrottle = settingsSecondaryThrottle; } else if (status != ErrorCodes::NoSuchKey) { if (!status.isOK()) return status; settings._migrationWriteConcern = WriteConcernOptions(); status = settings._migrationWriteConcern->parse(settingsMigrationWriteConcernElem.Obj()); if (!status.isOK()) return status; } } { bool settingsWaitForDelete; Status status = bsonExtractBooleanField(source, waitForDelete.name(), &settingsWaitForDelete); if (status != ErrorCodes::NoSuchKey) { if (!status.isOK()) return status; settings._waitForDelete = settingsWaitForDelete; } } } return settings; }
Status IsMasterResponse::initialize(const BSONObj& doc) { Status status = bsonExtractBooleanField(doc, kIsMasterFieldName, &_isMaster); if (!status.isOK()) { return status; } _isMasterSet = true; status = bsonExtractBooleanField(doc, kSecondaryFieldName, &_secondary); if (!status.isOK()) { return status; } _isSecondarySet = true; if (doc.hasField(kInfoFieldName)) { if (_isMaster || _secondary || !doc.hasField(kIsReplicaSetFieldName) || !doc[kIsReplicaSetFieldName].booleanSafe()) { return Status(ErrorCodes::FailedToParse, str::stream() << "Expected presence of \"" << kInfoFieldName << "\" field to indicate no valid config loaded, but other " "fields weren't as we expected"); } _configSet = false; return Status::OK(); } else { if (doc.hasField(kIsReplicaSetFieldName)) { return Status(ErrorCodes::FailedToParse, str::stream() << "Found \"" << kIsReplicaSetFieldName << "\" field which should indicate that no valid config " "is loaded, but we didn't also have an \"" << kInfoFieldName << "\" field as we expected"); } } status = bsonExtractStringField(doc, kSetNameFieldName, &_setName); if (!status.isOK()) { return status; } _setNameSet = true; status = bsonExtractIntegerField(doc, kSetVersionFieldName, &_setVersion); if (!status.isOK()) { return status; } _setVersionSet = true; if (doc.hasField(kHostsFieldName)) { BSONElement hostsElement; status = bsonExtractTypedField(doc, kHostsFieldName, Array, &hostsElement); if (!status.isOK()) { return status; } for (BSONObjIterator it(hostsElement.Obj()); it.more();) { BSONElement hostElement = it.next(); if (hostElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Elements in \"" << kHostsFieldName << "\" array of isMaster response must be of type " << typeName(String) << " but found type " << typeName(hostElement.type())); } _hosts.push_back(HostAndPort(hostElement.String())); } _hostsSet = true; } if (doc.hasField(kPassivesFieldName)) { BSONElement passivesElement; status = bsonExtractTypedField(doc, kPassivesFieldName, Array, &passivesElement); if (!status.isOK()) { return status; } for (BSONObjIterator it(passivesElement.Obj()); it.more();) { BSONElement passiveElement = it.next(); if (passiveElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Elements in \"" << kPassivesFieldName << "\" array of isMaster response must be of type " << typeName(String) << " but found type " << typeName(passiveElement.type())); } _passives.push_back(HostAndPort(passiveElement.String())); } _passivesSet = true; } if (doc.hasField(kArbitersFieldName)) { BSONElement arbitersElement; status = bsonExtractTypedField(doc, kArbitersFieldName, Array, &arbitersElement); if (!status.isOK()) { return status; } for (BSONObjIterator it(arbitersElement.Obj()); it.more();) { BSONElement arbiterElement = it.next(); if (arbiterElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Elements in \"" << kArbitersFieldName << "\" array of isMaster response must be of type " << typeName(String) << " but found type " << typeName(arbiterElement.type())); } _arbiters.push_back(HostAndPort(arbiterElement.String())); } _arbitersSet = true; } if (doc.hasField(kPrimaryFieldName)) { std::string primaryString; status = bsonExtractStringField(doc, kPrimaryFieldName, &primaryString); if (!status.isOK()) { return status; } _primary = HostAndPort(primaryString); _primarySet = true; } if (doc.hasField(kArbiterOnlyFieldName)) { status = bsonExtractBooleanField(doc, kArbiterOnlyFieldName, &_arbiterOnly); if (!status.isOK()) { return status; } _arbiterOnlySet = true; } if (doc.hasField(kPassiveFieldName)) { status = bsonExtractBooleanField(doc, kPassiveFieldName, &_passive); if (!status.isOK()) { return status; } _passiveSet = true; } if (doc.hasField(kHiddenFieldName)) { status = bsonExtractBooleanField(doc, kHiddenFieldName, &_hidden); if (!status.isOK()) { return status; } _hiddenSet = true; } if (doc.hasField(kBuildIndexesFieldName)) { status = bsonExtractBooleanField(doc, kBuildIndexesFieldName, &_buildIndexes); if (!status.isOK()) { return status; } _buildIndexesSet = true; } if (doc.hasField(kSlaveDelayFieldName)) { long long slaveDelaySecs; status = bsonExtractIntegerField(doc, kSlaveDelayFieldName, &slaveDelaySecs); if (!status.isOK()) { return status; } _slaveDelaySet = true; _slaveDelay = Seconds(slaveDelaySecs); } if (doc.hasField(kTagsFieldName)) { BSONElement tagsElement; status = bsonExtractTypedField(doc, kTagsFieldName, Object, &tagsElement); if (!status.isOK()) { return status; } for (BSONObjIterator it(tagsElement.Obj()); it.more();) { BSONElement tagElement = it.next(); if (tagElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Elements in \"" << kTagsFieldName << "\" obj " "of isMaster response must be of type " << typeName(String) << " but found type " << typeName(tagsElement.type())); } _tags[tagElement.fieldNameStringData().toString()] = tagElement.String(); } _tagsSet = true; } if (doc.hasField(kElectionIdFieldName)) { BSONElement electionIdElem; status = bsonExtractTypedField(doc, kElectionIdFieldName, jstOID, &electionIdElem); if (!status.isOK()) { return status; } _electionId = electionIdElem.OID(); } std::string meString; status = bsonExtractStringField(doc, kMeFieldName, &meString); if (!status.isOK()) { return status; } _me = HostAndPort(meString); _meSet = true; return Status::OK(); }
StatusWith<ShardCollectionType> ShardCollectionType::fromBSON(const BSONObj& source) { NamespaceString uuid; { std::string ns; Status status = bsonExtractStringField(source, ShardCollectionType::uuid.name(), &ns); if (!status.isOK()) return status; uuid = NamespaceString{ns}; } NamespaceString nss; { std::string ns; Status status = bsonExtractStringField(source, ShardCollectionType::ns.name(), &ns); if (!status.isOK()) { return status; } nss = NamespaceString{ns}; } OID epoch; { BSONElement oidElem; Status status = bsonExtractTypedField( source, ShardCollectionType::epoch.name(), BSONType::jstOID, &oidElem); if (!status.isOK()) return status; epoch = oidElem.OID(); } BSONElement collKeyPattern; Status status = bsonExtractTypedField( source, ShardCollectionType::keyPattern.name(), Object, &collKeyPattern); if (!status.isOK()) { return status; } BSONObj obj = collKeyPattern.Obj(); if (obj.isEmpty()) { return Status(ErrorCodes::ShardKeyNotFound, str::stream() << "Empty shard key. Failed to parse: " << source.toString()); } KeyPattern pattern(obj.getOwned()); BSONObj collation; { BSONElement defaultCollation; Status status = bsonExtractTypedField( source, ShardCollectionType::defaultCollation.name(), Object, &defaultCollation); if (status.isOK()) { BSONObj obj = defaultCollation.Obj(); if (obj.isEmpty()) { return Status(ErrorCodes::BadValue, "empty defaultCollation"); } collation = obj.getOwned(); } else if (status != ErrorCodes::NoSuchKey) { return status; } } bool unique; { Status status = bsonExtractBooleanField(source, ShardCollectionType::unique.name(), &unique); if (!status.isOK()) { return status; } } ShardCollectionType shardCollectionType(uuid, nss, epoch, pattern, collation, unique); // Below are optional fields. bool refreshing; { Status status = bsonExtractBooleanField(source, ShardCollectionType::refreshing.name(), &refreshing); if (status.isOK()) { shardCollectionType.setRefreshing(refreshing); } else if (status == ErrorCodes::NoSuchKey) { // The field is not set yet, which is okay. } else { return status; } } long long refreshSequenceNumber; { Status status = bsonExtractIntegerField( source, ShardCollectionType::refreshSequenceNumber.name(), &refreshSequenceNumber); if (status.isOK()) { shardCollectionType.setRefreshSequenceNumber(refreshSequenceNumber); } else if (status == ErrorCodes::NoSuchKey) { // The field is not set yet, which is okay. } else { return status; } } return shardCollectionType; }
StatusWith<MoveChunkRequest> MoveChunkRequest::createFromCommand(NamespaceString nss, const BSONObj& obj) { auto secondaryThrottleStatus = MigrationSecondaryThrottleOptions::createFromCommand(obj); if (!secondaryThrottleStatus.isOK()) { return secondaryThrottleStatus.getStatus(); } auto rangeStatus = ChunkRange::fromBSON(obj); if (!rangeStatus.isOK()) { return rangeStatus.getStatus(); } MoveChunkRequest request(std::move(nss), std::move(rangeStatus.getValue()), std::move(secondaryThrottleStatus.getValue())); { std::string shardStr; Status status = bsonExtractStringField(obj, kFromShardId, &shardStr); request._fromShardId = shardStr; if (!status.isOK()) { return status; } } { std::string shardStr; Status status = bsonExtractStringField(obj, kToShardId, &shardStr); request._toShardId = shardStr; if (!status.isOK()) { return status; } } { BSONElement epochElem; Status status = bsonExtractTypedField(obj, kEpoch, BSONType::jstOID, &epochElem); if (!status.isOK()) return status; request._versionEpoch = epochElem.OID(); } { Status status = bsonExtractBooleanFieldWithDefault(obj, kWaitForDelete, false, &request._waitForDelete); if (!status.isOK()) { return status; } } // Check for the deprecated name '_waitForDelete' if 'waitForDelete' was false. if (!request._waitForDelete) { Status status = bsonExtractBooleanFieldWithDefault( obj, kWaitForDeleteDeprecated, false, &request._waitForDelete); if (!status.isOK()) { return status; } } { long long maxChunkSizeBytes; Status status = bsonExtractIntegerField(obj, kMaxChunkSizeBytes, &maxChunkSizeBytes); if (!status.isOK()) { return status; } request._maxChunkSizeBytes = static_cast<int64_t>(maxChunkSizeBytes); } { // TODO: delete this block in 3.8 bool takeDistLock = false; Status status = bsonExtractBooleanField(obj, kTakeDistLock, &takeDistLock); if (status.isOK() && takeDistLock) { return Status{ErrorCodes::IncompatibleShardingConfigVersion, str::stream() << "Request received from an older, incompatible mongodb version"}; } } return request; }
StatusWith<ShardType> ShardingCatalogManager::_validateHostAsShard( OperationContext* opCtx, std::shared_ptr<RemoteCommandTargeter> targeter, const std::string* shardProposedName, const ConnectionString& connectionString) { auto swCommandResponse = _runCommandForAddShard( opCtx, targeter.get(), NamespaceString::kAdminDb, BSON("isMaster" << 1)); if (swCommandResponse.getStatus() == ErrorCodes::IncompatibleServerVersion) { return swCommandResponse.getStatus().withReason( str::stream() << "Cannot add " << connectionString.toString() << " as a shard because its binary version is not compatible with " "the cluster's featureCompatibilityVersion."); } else if (!swCommandResponse.isOK()) { return swCommandResponse.getStatus(); } // Check for a command response error auto resIsMasterStatus = std::move(swCommandResponse.getValue().commandStatus); if (!resIsMasterStatus.isOK()) { return resIsMasterStatus.withContext(str::stream() << "Error running isMaster against " << targeter->connectionString().toString()); } auto resIsMaster = std::move(swCommandResponse.getValue().response); // Fail if the node being added is a mongos. const std::string msg = resIsMaster.getStringField("msg"); if (msg == "isdbgrid") { return {ErrorCodes::IllegalOperation, "cannot add a mongos as a shard"}; } // Extract the maxWireVersion so we can verify that the node being added has a binary version // greater than or equal to the cluster's featureCompatibilityVersion. We expect an incompatible // binary node to be unable to communicate, returning an IncompatibleServerVersion error, // because of our internal wire version protocol. So we can safely invariant here that the node // is compatible. long long maxWireVersion; Status status = bsonExtractIntegerField(resIsMaster, "maxWireVersion", &maxWireVersion); if (!status.isOK()) { return status.withContext(str::stream() << "isMaster returned invalid 'maxWireVersion' " << "field when attempting to add " << connectionString.toString() << " as a shard"); } if (serverGlobalParams.featureCompatibility.getVersion() > ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo40) { // If the cluster's FCV is 4.2, or upgrading to / downgrading from, the node being added // must be a v4.2 binary. invariant(maxWireVersion == WireVersion::LATEST_WIRE_VERSION); } else { // If the cluster's FCV is 4.0, the node being added must be a v4.0 or v4.2 binary. invariant(serverGlobalParams.featureCompatibility.getVersion() == ServerGlobalParams::FeatureCompatibility::Version::kFullyDowngradedTo40); invariant(maxWireVersion >= WireVersion::LATEST_WIRE_VERSION - 1); } // Check whether there is a master. If there isn't, the replica set may not have been // initiated. If the connection is a standalone, it will return true for isMaster. bool isMaster; status = bsonExtractBooleanField(resIsMaster, "ismaster", &isMaster); if (!status.isOK()) { return status.withContext(str::stream() << "isMaster returned invalid 'ismaster' " << "field when attempting to add " << connectionString.toString() << " as a shard"); } if (!isMaster) { return {ErrorCodes::NotMaster, str::stream() << connectionString.toString() << " does not have a master. If this is a replica set, ensure that it has a" << " healthy primary and that the set has been properly initiated."}; } const std::string providedSetName = connectionString.getSetName(); const std::string foundSetName = resIsMaster["setName"].str(); // Make sure the specified replica set name (if any) matches the actual shard's replica set if (providedSetName.empty() && !foundSetName.empty()) { return {ErrorCodes::OperationFailed, str::stream() << "host is part of set " << foundSetName << "; " << "use replica set url format " << "<setname>/<server1>,<server2>, ..."}; } if (!providedSetName.empty() && foundSetName.empty()) { return {ErrorCodes::OperationFailed, str::stream() << "host did not return a set name; " << "is the replica set still initializing? " << resIsMaster}; } // Make sure the set name specified in the connection string matches the one where its hosts // belong into if (!providedSetName.empty() && (providedSetName != foundSetName)) { return {ErrorCodes::OperationFailed, str::stream() << "the provided connection string (" << connectionString.toString() << ") does not match the actual set name " << foundSetName}; } // Is it a config server? if (resIsMaster.hasField("configsvr")) { return {ErrorCodes::OperationFailed, str::stream() << "Cannot add " << connectionString.toString() << " as a shard since it is a config server"}; } // If the shard is part of a replica set, make sure all the hosts mentioned in the connection // string are part of the set. It is fine if not all members of the set are mentioned in the // connection string, though. if (!providedSetName.empty()) { std::set<std::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 } } for (const auto& hostEntry : connectionString.getServers()) { const auto& host = hostEntry.toString(); // host:port if (hostSet.find(host) == hostSet.end()) { return {ErrorCodes::OperationFailed, str::stream() << "in seed list " << connectionString.toString() << ", host " << host << " does not belong to replica set " << foundSetName << "; found " << resIsMaster.toString()}; } } } std::string actualShardName; if (shardProposedName) { actualShardName = *shardProposedName; } else if (!foundSetName.empty()) { // Default it to the name of the replica set actualShardName = foundSetName; } // Disallow adding shard replica set with name 'config' if (actualShardName == NamespaceString::kConfigDb) { return {ErrorCodes::BadValue, "use of shard replica set with name 'config' is not allowed"}; } // Retrieve the most up to date connection string that we know from the replica set monitor (if // this is a replica set shard, otherwise it will be the same value as connectionString). ConnectionString actualShardConnStr = targeter->connectionString(); ShardType shard; shard.setName(actualShardName); shard.setHost(actualShardConnStr.toString()); shard.setState(ShardType::ShardState::kShardAware); return shard; }
StatusWith<ShardType> ShardingCatalogManagerImpl::_validateHostAsShard( OperationContext* opCtx, std::shared_ptr<RemoteCommandTargeter> targeter, const std::string* shardProposedName, const ConnectionString& connectionString) { // Check if the node being added is a mongos or a version of mongod too old to speak the current // communication protocol. auto swCommandResponse = _runCommandForAddShard(opCtx, targeter.get(), "admin", BSON("isMaster" << 1)); if (!swCommandResponse.isOK()) { if (swCommandResponse.getStatus() == ErrorCodes::RPCProtocolNegotiationFailed) { // Mongos to mongos commands are no longer supported in the wire protocol // (because mongos does not support OP_COMMAND), similarly for a new mongos // and an old mongod. So the call will fail in such cases. // TODO: If/When mongos ever supports opCommands, this logic will break because // cmdStatus will be OK. return {ErrorCodes::RPCProtocolNegotiationFailed, str::stream() << targeter->connectionString().toString() << " does not recognize the RPC protocol being used. This is" << " likely because it contains a node that is a mongos or an old" << " version of mongod."}; } else { return swCommandResponse.getStatus(); } } // Check for a command response error auto resIsMasterStatus = std::move(swCommandResponse.getValue().commandStatus); if (!resIsMasterStatus.isOK()) { return {resIsMasterStatus.code(), str::stream() << "Error running isMaster against " << targeter->connectionString().toString() << ": " << causedBy(resIsMasterStatus)}; } auto resIsMaster = std::move(swCommandResponse.getValue().response); // Check that the node being added is a new enough version. // If we're running this code, that means the mongos that the addShard request originated from // must be at least version 3.4 (since 3.2 mongoses don't know about the _configsvrAddShard // command). Since it is illegal to have v3.4 mongoses with v3.2 shards, we should reject // adding any shards that are not v3.4. We can determine this by checking that the // maxWireVersion reported in isMaster is at least COMMANDS_ACCEPT_WRITE_CONCERN. // TODO(SERVER-25623): This approach won't work to prevent v3.6 mongoses from adding v3.4 // shards, so we'll have to rethink this during the 3.5 development cycle. long long maxWireVersion; Status status = bsonExtractIntegerField(resIsMaster, "maxWireVersion", &maxWireVersion); if (!status.isOK()) { return Status(status.code(), str::stream() << "isMaster returned invalid 'maxWireVersion' " << "field when attempting to add " << connectionString.toString() << " as a shard: " << status.reason()); } if (maxWireVersion < WireVersion::COMMANDS_ACCEPT_WRITE_CONCERN) { return Status(ErrorCodes::IncompatibleServerVersion, str::stream() << "Cannot add " << connectionString.toString() << " as a shard because we detected a mongod with server " "version older than 3.4.0. It is invalid to add v3.2 and " "older shards through a v3.4 mongos."); } // Check whether there is a master. If there isn't, the replica set may not have been // initiated. If the connection is a standalone, it will return true for isMaster. bool isMaster; status = bsonExtractBooleanField(resIsMaster, "ismaster", &isMaster); if (!status.isOK()) { return Status(status.code(), str::stream() << "isMaster returned invalid 'ismaster' " << "field when attempting to add " << connectionString.toString() << " as a shard: " << status.reason()); } if (!isMaster) { return {ErrorCodes::NotMaster, str::stream() << connectionString.toString() << " does not have a master. If this is a replica set, ensure that it has a" << " healthy primary and that the set has been properly initiated."}; } const std::string providedSetName = connectionString.getSetName(); const std::string foundSetName = resIsMaster["setName"].str(); // Make sure the specified replica set name (if any) matches the actual shard's replica set if (providedSetName.empty() && !foundSetName.empty()) { return {ErrorCodes::OperationFailed, str::stream() << "host is part of set " << foundSetName << "; " << "use replica set url format " << "<setname>/<server1>,<server2>, ..."}; } if (!providedSetName.empty() && foundSetName.empty()) { return {ErrorCodes::OperationFailed, str::stream() << "host did not return a set name; " << "is the replica set still initializing? " << resIsMaster}; } // Make sure the set name specified in the connection string matches the one where its hosts // belong into if (!providedSetName.empty() && (providedSetName != foundSetName)) { return {ErrorCodes::OperationFailed, str::stream() << "the provided connection string (" << connectionString.toString() << ") does not match the actual set name " << foundSetName}; } // Is it a config server? if (resIsMaster.hasField("configsvr")) { return {ErrorCodes::OperationFailed, str::stream() << "Cannot add " << connectionString.toString() << " as a shard since it is a config server"}; } // If the shard is part of a replica set, make sure all the hosts mentioned in the connection // string are part of the set. It is fine if not all members of the set are mentioned in the // connection string, though. if (!providedSetName.empty()) { std::set<std::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 } } for (const auto& hostEntry : connectionString.getServers()) { const auto& host = hostEntry.toString(); // host:port if (hostSet.find(host) == hostSet.end()) { return {ErrorCodes::OperationFailed, str::stream() << "in seed list " << connectionString.toString() << ", host " << host << " does not belong to replica set " << foundSetName << "; found " << resIsMaster.toString()}; } } } std::string actualShardName; if (shardProposedName) { actualShardName = *shardProposedName; } else if (!foundSetName.empty()) { // Default it to the name of the replica set actualShardName = foundSetName; } // Disallow adding shard replica set with name 'config' if (actualShardName == NamespaceString::kConfigDb) { return {ErrorCodes::BadValue, "use of shard replica set with name 'config' is not allowed"}; } // Retrieve the most up to date connection string that we know from the replica set monitor (if // this is a replica set shard, otherwise it will be the same value as connectionString). ConnectionString actualShardConnStr = targeter->connectionString(); ShardType shard; shard.setName(actualShardName); shard.setHost(actualShardConnStr.toString()); shard.setState(ShardType::ShardState::kShardAware); return shard; }
StatusWith<MongosType> MongosType::fromBSON(const BSONObj& source) { MongosType mt; { std::string mtName; Status status = bsonExtractStringField(source, name.name(), &mtName); if (!status.isOK()) return status; mt._name = mtName; } { BSONElement mtPingElem; Status status = bsonExtractTypedField(source, ping.name(), BSONType::Date, &mtPingElem); if (!status.isOK()) return status; mt._ping = mtPingElem.date(); } { long long mtUptime; Status status = bsonExtractIntegerField(source, uptime.name(), &mtUptime); if (!status.isOK()) return status; mt._uptime = mtUptime; } { bool mtWaiting; Status status = bsonExtractBooleanField(source, waiting.name(), &mtWaiting); if (!status.isOK()) return status; mt._waiting = mtWaiting; } if (source.hasField(mongoVersion.name())) { std::string mtMongoVersion; Status status = bsonExtractStringField(source, mongoVersion.name(), &mtMongoVersion); if (!status.isOK()) return status; mt._mongoVersion = mtMongoVersion; } if (source.hasField(configVersion.name())) { long long mtConfigVersion; Status status = bsonExtractIntegerField(source, configVersion.name(), &mtConfigVersion); if (!status.isOK()) return status; mt._configVersion = mtConfigVersion; } if (source.hasField(advisoryHostFQDNs.name())) { mt._advisoryHostFQDNs = std::vector<std::string>(); BSONElement array; Status status = bsonExtractTypedField(source, advisoryHostFQDNs.name(), Array, &array); if (!status.isOK()) return status; BSONObjIterator it(array.Obj()); while (it.more()) { BSONElement arrayElement = it.next(); if (arrayElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Elements in \"" << advisoryHostFQDNs.name() << "\" array must be strings but found " << typeName(arrayElement.type())); } mt._advisoryHostFQDNs->push_back(arrayElement.String()); } } return mt; }
StatusWith<TextMatchExpressionBase::TextParams> ExtensionsCallback::extractTextMatchExpressionParams(BSONElement text) { TextMatchExpressionBase::TextParams params; if (text.type() != Object) { return {ErrorCodes::BadValue, "$text expects an object"}; } BSONObj queryObj = text.Obj(); // // Parse required fields. // Status queryStatus = bsonExtractStringField(queryObj, "$search", ¶ms.query); if (!queryStatus.isOK()) { return queryStatus; } // // Parse optional fields. // int expectedFieldCount = 1; Status languageStatus = bsonExtractStringField(queryObj, "$language", ¶ms.language); if (languageStatus == ErrorCodes::TypeMismatch) { return languageStatus; } else if (languageStatus == ErrorCodes::NoSuchKey) { params.language = std::string(); } else { invariantOK(languageStatus); expectedFieldCount++; } Status caseSensitiveStatus = bsonExtractBooleanField(queryObj, "$caseSensitive", ¶ms.caseSensitive); if (caseSensitiveStatus == ErrorCodes::TypeMismatch) { return caseSensitiveStatus; } else if (caseSensitiveStatus == ErrorCodes::NoSuchKey) { params.caseSensitive = TextMatchExpressionBase::kCaseSensitiveDefault; } else { invariantOK(caseSensitiveStatus); expectedFieldCount++; } Status diacriticSensitiveStatus = bsonExtractBooleanField(queryObj, "$diacriticSensitive", ¶ms.diacriticSensitive); if (diacriticSensitiveStatus == ErrorCodes::TypeMismatch) { return diacriticSensitiveStatus; } else if (diacriticSensitiveStatus == ErrorCodes::NoSuchKey) { params.diacriticSensitive = TextMatchExpressionBase::kDiacriticSensitiveDefault; } else { invariantOK(diacriticSensitiveStatus); expectedFieldCount++; } if (queryObj.nFields() != expectedFieldCount) { return {ErrorCodes::BadValue, "extra fields in $text"}; } return {std::move(params)}; }
StatusWith<ShardType> ShardingCatalogManagerImpl::_validateHostAsShard( OperationContext* txn, std::shared_ptr<RemoteCommandTargeter> targeter, const std::string* shardProposedName, const ConnectionString& connectionString) { // Check whether any host in the connection is already part of the cluster. Grid::get(txn)->shardRegistry()->reload(txn); for (const auto& hostAndPort : connectionString.getServers()) { std::shared_ptr<Shard> shard; shard = Grid::get(txn)->shardRegistry()->getShardNoReload(hostAndPort.toString()); if (shard) { return {ErrorCodes::OperationFailed, str::stream() << "'" << hostAndPort.toString() << "' " << "is already a member of the existing shard '" << shard->getConnString().toString() << "' (" << shard->getId() << ")."}; } } // Check for mongos and older version mongod connections, and whether the hosts // can be found for the user specified replset. auto swCommandResponse = _runCommandForAddShard(txn, targeter.get(), "admin", BSON("isMaster" << 1)); if (!swCommandResponse.isOK()) { if (swCommandResponse.getStatus() == ErrorCodes::RPCProtocolNegotiationFailed) { // Mongos to mongos commands are no longer supported in the wire protocol // (because mongos does not support OP_COMMAND), similarly for a new mongos // and an old mongod. So the call will fail in such cases. // TODO: If/When mongos ever supports opCommands, this logic will break because // cmdStatus will be OK. return {ErrorCodes::RPCProtocolNegotiationFailed, str::stream() << targeter->connectionString().toString() << " does not recognize the RPC protocol being used. This is" << " likely because it contains a node that is a mongos or an old" << " version of mongod."}; } else { return swCommandResponse.getStatus(); } } // Check for a command response error auto resIsMasterStatus = std::move(swCommandResponse.getValue().commandStatus); if (!resIsMasterStatus.isOK()) { return {resIsMasterStatus.code(), str::stream() << "Error running isMaster against " << targeter->connectionString().toString() << ": " << causedBy(resIsMasterStatus)}; } auto resIsMaster = std::move(swCommandResponse.getValue().response); // Check whether there is a master. If there isn't, the replica set may not have been // initiated. If the connection is a standalone, it will return true for isMaster. bool isMaster; Status status = bsonExtractBooleanField(resIsMaster, "ismaster", &isMaster); if (!status.isOK()) { return Status(status.code(), str::stream() << "isMaster returned invalid 'ismaster' " << "field when attempting to add " << connectionString.toString() << " as a shard: " << status.reason()); } if (!isMaster) { return {ErrorCodes::NotMaster, str::stream() << connectionString.toString() << " does not have a master. If this is a replica set, ensure that it has a" << " healthy primary and that the set has been properly initiated."}; } const string providedSetName = connectionString.getSetName(); const string foundSetName = resIsMaster["setName"].str(); // Make sure the specified replica set name (if any) matches the actual shard's replica set if (providedSetName.empty() && !foundSetName.empty()) { return {ErrorCodes::OperationFailed, str::stream() << "host is part of set " << foundSetName << "; " << "use replica set url format " << "<setname>/<server1>,<server2>, ..."}; } if (!providedSetName.empty() && foundSetName.empty()) { return {ErrorCodes::OperationFailed, str::stream() << "host did not return a set name; " << "is the replica set still initializing? " << resIsMaster}; } // Make sure the set name specified in the connection string matches the one where its hosts // belong into if (!providedSetName.empty() && (providedSetName != foundSetName)) { return {ErrorCodes::OperationFailed, str::stream() << "the provided connection string (" << connectionString.toString() << ") does not match the actual set name " << foundSetName}; } // Is it a config server? if (resIsMaster.hasField("configsvr")) { return {ErrorCodes::OperationFailed, str::stream() << "Cannot add " << connectionString.toString() << " as a shard since it is a config server"}; } // If the shard is part of a replica set, make sure all the hosts mentioned in the connection // string are part of the set. It is fine if not all members of the set are mentioned in the // connection string, though. if (!providedSetName.empty()) { std::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 = connectionString.getServers(); for (size_t i = 0; i < hosts.size(); i++) { const string host = hosts[i].toString(); // host:port if (hostSet.find(host) == hostSet.end()) { return {ErrorCodes::OperationFailed, str::stream() << "in seed list " << connectionString.toString() << ", host " << host << " does not belong to replica set " << foundSetName << "; found " << resIsMaster.toString()}; } } } string actualShardName; if (shardProposedName) { actualShardName = *shardProposedName; } else if (!foundSetName.empty()) { // Default it to the name of the replica set actualShardName = foundSetName; } // Disallow adding shard replica set with name 'config' if (actualShardName == "config") { return {ErrorCodes::BadValue, "use of shard replica set with name 'config' is not allowed"}; } // Retrieve the most up to date connection string that we know from the replica set monitor (if // this is a replica set shard, otherwise it will be the same value as connectionString). ConnectionString actualShardConnStr = targeter->connectionString(); ShardType shard; shard.setName(actualShardName); shard.setHost(actualShardConnStr.toString()); return shard; }
Status _parseAndValidateInput(BSONObj cmdObj, CreateUserArgs* parsedArgs) const { unordered_set<std::string> validFieldNames; validFieldNames.insert("createUser"); validFieldNames.insert("user"); validFieldNames.insert("pwd"); validFieldNames.insert("userSource"); validFieldNames.insert("roles"); validFieldNames.insert("readOnly"); validFieldNames.insert("otherDBRoles"); // Iterate through all fields in command object and make sure there are no unexpected // ones. for (BSONObjIterator iter(cmdObj); iter.more(); iter.next()) { StringData fieldName = (*iter).fieldNameStringData(); if (!validFieldNames.count(fieldName.toString())) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "\"" << fieldName << "\" is not " "a valid argument to createUser"); } } Status status = bsonExtractStringField(cmdObj, "user", &parsedArgs->userName); if (!status.isOK()) { return status; } if (cmdObj.hasField("pwd")) { parsedArgs->hasPassword = true; status = bsonExtractStringField(cmdObj, "pwd", &parsedArgs->clearTextPassword); if (!status.isOK()) { return status; } } if (cmdObj.hasField("userSource")) { parsedArgs->hasUserSource = true; status = bsonExtractStringField(cmdObj, "userSource", &parsedArgs->userSource); if (!status.isOK()) { return status; } } if (cmdObj.hasField("readOnly")) { parsedArgs->hasReadOnly = true; status = bsonExtractBooleanField(cmdObj, "readOnly", &parsedArgs->readOnly); if (!status.isOK()) { return status; } } if (cmdObj.hasField("extraData")) { parsedArgs->hasExtraData = true; BSONElement element; status = bsonExtractTypedField(cmdObj, "extraData", Object, &element); if (!status.isOK()) { return status; } parsedArgs->extraData = element.Obj(); } if (cmdObj.hasField("roles")) { parsedArgs->hasRoles = true; BSONElement element; status = bsonExtractTypedField(cmdObj, "roles", Array, &element); if (!status.isOK()) { return status; } parsedArgs->roles = BSONArray(element.Obj()); } if (cmdObj.hasField("otherDBRoles")) { parsedArgs->hasOtherDBRoles = true; BSONElement element; status = bsonExtractTypedField(cmdObj, "otherDBRoles", Object, &element); if (!status.isOK()) { return status; } parsedArgs->otherDBRoles = element.Obj(); } if (parsedArgs->hasPassword && parsedArgs->hasUserSource) { return Status(ErrorCodes::BadValue, "User objects can't have both 'pwd' and 'userSource'"); } if (!parsedArgs->hasPassword && !parsedArgs->hasUserSource) { return Status(ErrorCodes::BadValue, "User objects must have one of 'pwd' and 'userSource'"); } if (parsedArgs->hasRoles && parsedArgs->hasReadOnly) { return Status(ErrorCodes::BadValue, "User objects can't have both 'roles' and 'readOnly'"); } return Status::OK(); }
StatusWith<ChunkType> ChunkType::fromBSON(const BSONObj& source) { ChunkType chunk; { std::string chunkName; Status status = bsonExtractStringField(source, name.name(), &chunkName); if (!status.isOK()) return status; chunk._name = chunkName; } { std::string chunkNS; Status status = bsonExtractStringField(source, ns.name(), &chunkNS); if (!status.isOK()) return status; chunk._ns = chunkNS; } { BSONElement chunkMinElement; Status status = bsonExtractTypedField(source, min.name(), Object, &chunkMinElement); if (!status.isOK()) return status; chunk._min = chunkMinElement.Obj().getOwned(); } { BSONElement chunkMaxElement; Status status = bsonExtractTypedField(source, max.name(), Object, &chunkMaxElement); if (!status.isOK()) return status; chunk._max = chunkMaxElement.Obj().getOwned(); } { std::string chunkShard; Status status = bsonExtractStringField(source, shard.name(), &chunkShard); if (!status.isOK()) return status; chunk._shard = chunkShard; } { bool chunkJumbo; Status status = bsonExtractBooleanField(source, jumbo.name(), &chunkJumbo); if (status.isOK()) { chunk._jumbo = chunkJumbo; } else if (status == ErrorCodes::NoSuchKey) { // Jumbo status is missing, so it will be presumed false } else { return status; } } // // ChunkVersion backward compatibility logic contained in ChunkVersion // // ChunkVersion is currently encoded as { 'version': [<TS>,<OID>] } if (ChunkVersion::canParseBSON(source, version())) { chunk._version = ChunkVersion::fromBSON(source, version()); } else if (ChunkVersion::canParseBSON(source, DEPRECATED_lastmod())) { chunk._version = ChunkVersion::fromBSON(source, DEPRECATED_lastmod()); } return chunk; }
StatusWith<ShardType> ShardType::fromBSON(const BSONObj& source) { ShardType shard; { std::string shardName; Status status = bsonExtractStringField(source, name.name(), &shardName); if (!status.isOK()) return status; shard._name = shardName; } { std::string shardHost; Status status = bsonExtractStringField(source, host.name(), &shardHost); if (!status.isOK()) return status; shard._host = shardHost; } { bool isShardDraining; Status status = bsonExtractBooleanField(source, draining.name(), &isShardDraining); if (status.isOK()) { shard._draining = isShardDraining; } else if (status == ErrorCodes::NoSuchKey) { // draining field can be mssing in which case it is presumed false } else { return status; } } { long long shardMaxSizeMB; // maxSizeMB == 0 means there's no limitation to space usage. Status status = bsonExtractIntegerField(source, maxSizeMB.name(), &shardMaxSizeMB); if (status.isOK()) { shard._maxSizeMB = shardMaxSizeMB; } else if (status == ErrorCodes::NoSuchKey) { // maxSizeMB field can be missing in which case it is presumed false } else { return status; } } if (source.hasField(tags.name())) { shard._tags = std::vector<std::string>(); BSONElement tagsElement; Status status = bsonExtractTypedField(source, tags.name(), Array, &tagsElement); if (!status.isOK()) return status; BSONObjIterator it(tagsElement.Obj()); while (it.more()) { BSONElement tagElement = it.next(); if (tagElement.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Elements in \"" << tags.name() << "\" array must be strings but found " << typeName(tagElement.type())); } shard._tags->push_back(tagElement.String()); } } return shard; }
Status ReplSetHeartbeatResponseV1::initialize(const BSONObj& doc) { Status status = bsonCheckOnlyHasFields("ReplSetHeartbeatResponse", doc, kLegalHeartbeatFieldNames); if (!status.isOK()) return status; status = bsonExtractBooleanField(doc, kIsReplSetFieldName, &_isReplSet); if (!status.isOK()) return status; status = bsonExtractStringField(doc, kReplSetFieldName, &_setName); if (!status.isOK()) return status; long long stateInt; status = bsonExtractIntegerField(doc, kMemberStateFieldName, &stateInt); if (!status.isOK()) return status; if (stateInt < 0 || stateInt > MemberState::RS_MAX) { return Status(ErrorCodes::BadValue, str::stream() << "Value for \"" << kMemberStateFieldName << "\" in response to replSetHeartbeat is " "out of range; legal values are non-negative and no more than " << MemberState::RS_MAX); } _state = MemberState(static_cast<int>(stateInt)); // extracting the lastCommittedOp is a bit of a process BSONObj lastOpTime = doc[kLastOpTimeFieldName].Obj(); Timestamp ts; status = bsonExtractTimestampField(lastOpTime, kOpTimeFieldName, &ts); if (!status.isOK()) return status; long long term; status = bsonExtractIntegerField(lastOpTime, kTermFieldName, &term); if (!status.isOK()) return status; _lastOpTime = OpTime(lastOpTime[kOpTimeFieldName].timestamp(), lastOpTime[kTermFieldName].Long()); status = bsonExtractStringField(doc, kSyncSourceFieldName, &_syncingTo); if (!status.isOK()) return status; status = bsonExtractIntegerField(doc, kConfigVersionFieldName, &_configVersion); if (!status.isOK()) return status; status = bsonExtractIntegerField(doc, kPrimaryIdFieldName, &_primaryId); if (!status.isOK()) return status; status = bsonExtractIntegerField(doc, kTermFieldName, &_term); if (!status.isOK()) return status; const BSONElement hasDataElement = doc[kHasDataFieldName]; _hasDataSet = !hasDataElement.eoo(); _hasData = hasDataElement.trueValue(); const BSONElement rsConfigElement = doc[kConfigFieldName]; if (rsConfigElement.eoo()) { _configSet = false; _config = ReplicaSetConfig(); return Status::OK(); } else if (rsConfigElement.type() != Object) { return Status(ErrorCodes::TypeMismatch, str::stream() << "Expected \"" << kConfigFieldName << "\" in response to replSetHeartbeat to have type " "Object, but found " << typeName(rsConfigElement.type())); } _configSet = true; return _config.initialize(rsConfigElement.Obj()); }