Status parseAndValidateRolePrivilegeManipulationCommands(const BSONObj& cmdObj, const StringData& cmdName, const std::string& dbname, RoleName* parsedRoleName, PrivilegeVector* parsedPrivileges, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert("privileges"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } BSONObjBuilder roleObjBuilder; // Parse role name std::string roleName; status = bsonExtractStringField(cmdObj, cmdName, &roleName); if (!status.isOK()) { return status; } *parsedRoleName = RoleName(roleName, dbname); // Parse privileges BSONElement privilegesElement; status = bsonExtractTypedField(cmdObj, "privileges", Array, &privilegesElement); if (!status.isOK()) { return status; } status = parseAndValidatePrivilegeArray(BSONArray(privilegesElement.Obj()), parsedPrivileges); if (!status.isOK()) { return status; } if (!parsedPrivileges->size()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << cmdName << " command requires a non-empty " "\"privileges\" array"); } return Status::OK(); }
Status parseRolePossessionManipulationCommands(const BSONObj& cmdObj, const StringData& cmdName, const StringData& rolesFieldName, const std::string& dbname, std::string* parsedName, vector<RoleName>* parsedRoleNames, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert(cmdName.toString()); validFieldNames.insert(rolesFieldName.toString()); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, cmdName, validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } status = bsonExtractStringField(cmdObj, cmdName, parsedName); if (!status.isOK()) { return status; } BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, rolesFieldName, Array, &rolesElement); if (!status.isOK()) { return status; } status = parseRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), dbname, rolesFieldName, parsedRoleNames); if (!status.isOK()) { return status; } if (!parsedRoleNames->size()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << cmdName << " command requires a non-empty \"" << rolesFieldName << "\" array"); } return Status::OK(); }
// static StatusWith<RollbackFixUpInfo::IndexOpType> RollbackFixUpInfo::IndexDescription::parseOpType( const BSONObj& doc) { std::string opTypeStr; auto status = bsonExtractStringField(doc, "operationType"_sd, &opTypeStr); if (!status.isOK()) { return status; } if ("create" == opTypeStr) { return RollbackFixUpInfo::IndexOpType::kCreate; } else if ("drop" == opTypeStr) { return RollbackFixUpInfo::IndexOpType::kDrop; } else if ("updateTTL" == opTypeStr) { return RollbackFixUpInfo::IndexOpType::kUpdateTTL; } return Status(ErrorCodes::FailedToParse, str::stream() << "Unrecognized RollbackFixUpInfo::IndexOpType: " << opTypeStr); }
Status ReplSetHeartbeatArgs::initialize(const BSONObj& argsObj) { Status status = bsonCheckOnlyHasFields("ReplSetHeartbeatArgs", argsObj, kLegalHeartbeatFieldNames); if (!status.isOK()) return status; status = bsonExtractBooleanFieldWithDefault(argsObj, kCheckEmptyFieldName, false, &_checkEmpty); if (!status.isOK()) return status; _hasCheckEmpty = true; status = bsonExtractIntegerField(argsObj, kProtocolVersionFieldName, &_protocolVersion); if (!status.isOK()) return status; _hasProtocolVersion = true; status = bsonExtractIntegerField(argsObj, kConfigVersionFieldName, &_configVersion); if (!status.isOK()) return status; _hasConfigVersion = true; status = bsonExtractIntegerFieldWithDefault(argsObj, kSenderIdFieldName, -1, &_senderId); if (!status.isOK()) return status; _hasSenderId = true; status = bsonExtractStringField(argsObj, kSetNameFieldName, &_setName); if (!status.isOK()) return status; _hasSetName = true; std::string hostAndPortString; status = bsonExtractStringFieldWithDefault(argsObj, kSenderHostFieldName, "", &hostAndPortString); if (!status.isOK()) return status; if (!hostAndPortString.empty()) { status = _senderHost.initialize(hostAndPortString); if (!status.isOK()) return status; _hasSenderHost = true; } return Status::OK(); }
StatusWith<ChunkType> ChunkType::fromShardBSON(const BSONObj& source, const OID& epoch) { ChunkType chunk; { BSONElement minKey; Status minKeyStatus = extractObject(source, minShardID.name(), &minKey); if (!minKeyStatus.isOK()) { return minKeyStatus; } BSONElement maxKey; Status maxKeyStatus = extractObject(source, max.name(), &maxKey); if (!maxKeyStatus.isOK()) { return maxKeyStatus; } if (SimpleBSONObjComparator::kInstance.evaluate(minKey.Obj() >= maxKey.Obj())) { return {ErrorCodes::FailedToParse, str::stream() << "min: " << minKey.Obj() << " should be less than max: " << maxKey.Obj()}; } chunk._min = minKey.Obj().getOwned(); chunk._max = maxKey.Obj().getOwned(); } { std::string chunkShard; Status status = bsonExtractStringField(source, shard.name(), &chunkShard); if (!status.isOK()) return status; chunk._shard = chunkShard; } { auto statusWithChunkVersion = ChunkVersion::parseFromBSONWithFieldAndSetEpoch(source, lastmod.name(), epoch); if (!statusWithChunkVersion.isOK()) { return statusWithChunkVersion.getStatus(); } chunk._version = std::move(statusWithChunkVersion.getValue()); } return chunk; }
StatusWith<ReadPreferenceSetting> ReadPreferenceSetting::fromBSON(const BSONObj& readPrefObj) { std::string modeStr; auto modeExtractStatus = bsonExtractStringField(readPrefObj, kModeFieldName, &modeStr); if (!modeExtractStatus.isOK()) { return modeExtractStatus; } ReadPreference mode; auto swReadPrefMode = parseReadPreferenceMode(modeStr); if (!swReadPrefMode.isOK()) { return swReadPrefMode.getStatus(); } mode = std::move(swReadPrefMode.getValue()); TagSet tags; BSONElement tagsElem; auto tagExtractStatus = bsonExtractTypedField(readPrefObj, kTagsFieldName, mongo::Array, &tagsElem); if (tagExtractStatus.isOK()) { tags = TagSet{BSONArray(tagsElem.Obj().getOwned())}; // In accordance with the read preference spec, passing the default wildcard tagset // '[{}]' is the same as not passing a TagSet at all. Furthermore, passing an empty // TagSet with a non-primary ReadPreference is equivalent to passing the wildcard // ReadPreference. if (tags == TagSet() || tags == TagSet::primaryOnly()) { tags = defaultTagSetForMode(mode); } // If we are using a user supplied TagSet, check that it is compatible with // the readPreference mode. else if (ReadPreference::PrimaryOnly == mode && (tags != TagSet::primaryOnly())) { return Status(ErrorCodes::BadValue, "Only empty tags are allowed with primary read preference"); } } else if (ErrorCodes::NoSuchKey == tagExtractStatus) { tags = defaultTagSetForMode(mode); } else { return tagExtractStatus; } return ReadPreferenceSetting(mode, tags); }
Status ReadConcernArgs::initialize(const BSONElement& readConcernElem) { if (readConcernElem.eoo()) { return Status::OK(); } dassert(readConcernElem.fieldNameStringData() == kReadConcernFieldName); if (!readConcernElem.isABSONObj()) { return Status(ErrorCodes::FailedToParse, str::stream() << kReadConcernFieldName << " field should be an object"); } BSONObj readConcernObj = readConcernElem.Obj(); if (readConcernObj.hasField(kAfterOpTimeFieldName)) { OpTime opTime; auto opTimeStatus = bsonExtractOpTimeField(readConcernObj, kAfterOpTimeFieldName, &opTime); if (!opTimeStatus.isOK()) { return opTimeStatus; } _opTime = opTime; } std::string levelString; auto readCommittedStatus = bsonExtractStringField(readConcernObj, kLevelFieldName, &levelString); if (readCommittedStatus.isOK()) { if (levelString == kLocalReadConcernStr) { _level = ReadConcernLevel::kLocalReadConcern; } else if (levelString == kMajorityReadConcernStr) { _level = ReadConcernLevel::kMajorityReadConcern; } else { return Status(ErrorCodes::FailedToParse, str::stream() << kReadConcernFieldName << '.' << kLevelFieldName << " must be either \"local\" or \"majority\""); } } else if (readCommittedStatus != ErrorCodes::NoSuchKey) { return readCommittedStatus; } return Status::OK(); }
Status parseUserRoleManipulationCommand(const BSONObj& cmdObj, const StringData& cmdName, const std::string& dbname, AuthorizationManager* authzManager, UserName* parsedUserName, vector<RoleName>* parsedRoleNames, BSONObj* parsedWriteConcern) { Status status = extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } std::string userNameStr; status = bsonExtractStringField(cmdObj, cmdName, &userNameStr); if (!status.isOK()) { return status; } *parsedUserName = UserName(userNameStr, dbname); BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } status = _extractRoleNamesFromBSONArray(BSONArray(rolesElement.Obj()), dbname, authzManager, parsedRoleNames); if (!status.isOK()) { return status; } if (!parsedRoleNames->size()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << cmdName << " command requires a non-empty" << " roles array"); } return Status::OK(); }
StatusWith<ControlBalancerRequest> ControlBalancerRequest::_parse(const BSONObj& obj, StringData commandString) { if (obj.firstElementFieldName() != commandString) { return {ErrorCodes::InternalError, str::stream() << "Expected to find a " << commandString << " command, but found " << obj}; } std::string actionString; Status status = bsonExtractStringField(obj, commandString, &actionString); if (!status.isOK()) { return status; } if (actionString == kStartAction) return ControlBalancerRequest(kStart); if (actionString == kStopAction) return ControlBalancerRequest(kStop); return {ErrorCodes::IllegalOperation, str::stream() << actionString << " is not a valid balancer control action"}; }
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; // extracting the lastCommittedOp is a bit of a process BSONObj lastCommittedOp = argsObj[kLastCommittedOpFieldName].Obj(); Timestamp ts; status = bsonExtractTimestampField(lastCommittedOp, kOpTimeFieldName, &ts); if (!status.isOK()) return status; long long term; status = bsonExtractIntegerField(lastCommittedOp, kTermFieldName, &term); if (!status.isOK()) return status; _lastCommittedOp = OpTime(lastCommittedOp[kOpTimeFieldName].timestamp(), lastCommittedOp[kTermFieldName].Long()); return Status::OK(); }
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(); }
/** * Validates that the roles array described by rolesElement is valid. * Also returns a new roles array (via the modifiedRolesArray output param) where any roles * from the input array that were listed as strings have been expanded to a full role document. * If includePossessionBools is true then the expanded roles documents will have "hasRole" * and "canDelegate" boolean fields (in addition to the "name" and "source" fields which are * there either way). */ Status _validateAndModifyRolesArray(const BSONElement& rolesElement, const std::string& dbname, AuthorizationManager* authzManager, bool includePossessionBools, BSONArray* modifiedRolesArray) { BSONArrayBuilder rolesBuilder; for (BSONObjIterator it(rolesElement.Obj()); it.more(); it.next()) { BSONElement element = *it; if (element.type() == String) { RoleName roleName(element.String(), dbname); if (!authzManager->roleExists(roleName)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << roleName.toString() << " does not name an existing role"); } if (includePossessionBools) { rolesBuilder.append(BSON("name" << element.String() << "source" << dbname << "hasRole" << true << "canDelegate" << false)); } else { rolesBuilder.append(BSON("name" << element.String() << "source" << dbname)); } } else if (element.type() == Object) { // Check that the role object is valid V2UserDocumentParser parser; BSONObj roleObj = element.Obj(); Status status = parser.checkValidRoleObject(roleObj, includePossessionBools); if (!status.isOK()) { return status; } // Check that the role actually exists std::string roleNameString; std::string roleSource; status = bsonExtractStringField(roleObj, "name", &roleNameString); if (!status.isOK()) { return status; } status = bsonExtractStringField(roleObj, "source", &roleSource); if (!status.isOK()) { return status; } RoleName roleName(roleNameString, roleSource); if (!authzManager->roleExists(roleName)) { return Status(ErrorCodes::RoleNotFound, mongoutils::str::stream() << roleName.toString() << " does not name an existing role"); } rolesBuilder.append(element); } else { return Status(ErrorCodes::UnsupportedFormat, "Values in 'roles' array must be sub-documents or strings"); } } *modifiedRolesArray = rolesBuilder.arr(); return Status::OK(); }
StatusWith<ChangeLogType> ChangeLogType::fromBSON(const BSONObj& source) { ChangeLogType changeLog; { std::string changeLogId; Status status = bsonExtractStringField(source, changeId.name(), &changeLogId); if (!status.isOK()) return status; changeLog._changeId = changeLogId; } { std::string changeLogServer; Status status = bsonExtractStringField(source, server.name(), &changeLogServer); if (!status.isOK()) return status; changeLog._server = changeLogServer; } { std::string changeLogShard; Status status = bsonExtractStringFieldWithDefault(source, shard.name(), "", &changeLogShard); if (!status.isOK()) return status; changeLog._shard = changeLogShard; } { std::string changeLogClientAddr; Status status = bsonExtractStringField(source, clientAddr.name(), &changeLogClientAddr); if (!status.isOK()) return status; changeLog._clientAddr = changeLogClientAddr; } { BSONElement changeLogTimeElem; Status status = bsonExtractTypedField(source, time.name(), Date, &changeLogTimeElem); if (!status.isOK()) return status; changeLog._time = changeLogTimeElem.date(); } { std::string changeLogWhat; Status status = bsonExtractStringField(source, what.name(), &changeLogWhat); if (!status.isOK()) return status; changeLog._what = changeLogWhat; } { std::string changeLogNs; Status status = bsonExtractStringFieldWithDefault(source, ns.name(), "", &changeLogNs); if (!status.isOK()) return status; changeLog._ns = changeLogNs; } { BSONElement changeLogDetailsElem; Status status = bsonExtractTypedField(source, details.name(), Object, &changeLogDetailsElem); if (!status.isOK()) return status; changeLog._details = changeLogDetailsElem.Obj().getOwned(); } return changeLog; }
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<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<ReadPreferenceSetting> ReadPreferenceSetting::fromInnerBSON(const BSONObj& readPrefObj) { std::string modeStr; auto modeExtractStatus = bsonExtractStringField(readPrefObj, kModeFieldName, &modeStr); if (!modeExtractStatus.isOK()) { return modeExtractStatus; } ReadPreference mode; auto swReadPrefMode = parseReadPreferenceMode(modeStr); if (!swReadPrefMode.isOK()) { return swReadPrefMode.getStatus(); } mode = std::move(swReadPrefMode.getValue()); TagSet tags; BSONElement tagsElem; auto tagExtractStatus = bsonExtractTypedField(readPrefObj, kTagsFieldName, mongo::Array, &tagsElem); if (tagExtractStatus.isOK()) { tags = TagSet{BSONArray(tagsElem.Obj().getOwned())}; // In accordance with the read preference spec, passing the default wildcard tagset // '[{}]' is the same as not passing a TagSet at all. Furthermore, passing an empty // TagSet with a non-primary ReadPreference is equivalent to passing the wildcard // ReadPreference. if (tags == TagSet() || tags == TagSet::primaryOnly()) { tags = defaultTagSetForMode(mode); } // If we are using a user supplied TagSet, check that it is compatible with // the readPreference mode. else if (ReadPreference::PrimaryOnly == mode && (tags != TagSet::primaryOnly())) { return Status(ErrorCodes::BadValue, "Only empty tags are allowed with primary read preference"); } } else if (ErrorCodes::NoSuchKey == tagExtractStatus) { tags = defaultTagSetForMode(mode); } else { return tagExtractStatus; } long long maxStalenessSecondsValue; auto maxStalenessSecondsExtractStatus = bsonExtractIntegerFieldWithDefault( readPrefObj, kMaxStalenessSecondsFieldName, 0, &maxStalenessSecondsValue); if (!maxStalenessSecondsExtractStatus.isOK()) { return maxStalenessSecondsExtractStatus; } if (maxStalenessSecondsValue && maxStalenessSecondsValue < 0) { return Status(ErrorCodes::BadValue, str::stream() << kMaxStalenessSecondsFieldName << " must be a non-negative integer"); } if (maxStalenessSecondsValue && maxStalenessSecondsValue >= Seconds::max().count()) { return Status(ErrorCodes::BadValue, str::stream() << kMaxStalenessSecondsFieldName << " value can not exceed " << Seconds::max().count()); } if (maxStalenessSecondsValue && maxStalenessSecondsValue < kMinimalMaxStalenessValue.count()) { return Status(ErrorCodes::MaxStalenessOutOfRange, str::stream() << kMaxStalenessSecondsFieldName << " value can not be less than " << kMinimalMaxStalenessValue.count()); } if ((mode == ReadPreference::PrimaryOnly) && maxStalenessSecondsValue) { return Status(ErrorCodes::BadValue, str::stream() << kMaxStalenessSecondsFieldName << " can not be set for the primary mode"); } return ReadPreferenceSetting(mode, tags, Seconds(maxStalenessSecondsValue)); }
Status extractMechanism(const BSONObj& cmdObj, std::string* mechanism) { return bsonExtractStringField(cmdObj, saslCommandMechanismFieldName, mechanism); }
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<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 configServerConnectionString; Status status = bsonExtractStringField( obj, kConfigServerConnectionString, &configServerConnectionString); if (!status.isOK()) { return status; } auto statusConfigServerCS = ConnectionString::parse(configServerConnectionString); if (!statusConfigServerCS.isOK()) { return statusConfigServerCS.getStatus(); } request._configServerCS = std::move(statusConfigServerCS.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; } } { Status status = bsonExtractBooleanFieldWithDefault(obj, kWaitForDelete, 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); } { Status status = bsonExtractBooleanFieldWithDefault(obj, kTakeDistLock, true, &request._takeDistLock); if (!status.isOK()) { return status; } } return request; }
// TODO: The bulk of the implementation of this will need to change once we're using the // new v2 authorization storage format. bool run(const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { std::string userName; std::string password; std::string userSource; // TODO: remove this. bool readOnly; // TODO: remove this. BSONElement extraData; BSONElement roles; if (cmdObj.hasField("pwd") && cmdObj.hasField("userSource")) { errmsg = "User objects can't have both 'pwd' and 'userSource'"; return false; } if (!cmdObj.hasField("pwd") && !cmdObj.hasField("userSource")) { errmsg = "User objects must have one of 'pwd' and 'userSource'"; return false; } if (cmdObj.hasField("roles") && cmdObj.hasField("readOnly")) { errmsg = "User objects can't have both 'roles' and 'readOnly'"; return false; } Status status = bsonExtractStringField(cmdObj, "user", &userName); if (!status.isOK()) { addStatus(Status(ErrorCodes::UserModificationFailed, "\"user\" string not specified"), result); return false; } status = bsonExtractStringFieldWithDefault(cmdObj, "pwd", "", &password); if (!status.isOK()) { addStatus(Status(ErrorCodes::UserModificationFailed, "Invalid \"pwd\" string"), result); return false; } status = bsonExtractStringFieldWithDefault(cmdObj, "userSource", "", &userSource); if (!status.isOK()) { addStatus(Status(ErrorCodes::UserModificationFailed, "Invalid \"userSource\" string"), result); return false; } status = bsonExtractBooleanFieldWithDefault(cmdObj, "readOnly", false, &readOnly); if (!status.isOK()) { addStatus(Status(ErrorCodes::UserModificationFailed, "Invalid \"readOnly\" boolean"), result); return false; } if (cmdObj.hasField("extraData")) { status = bsonExtractField(cmdObj, "extraData", &extraData); if (!status.isOK()) { addStatus(Status(ErrorCodes::UserModificationFailed, "Invalid \"extraData\" object"), result); return false; } } if (cmdObj.hasField("roles")) { status = bsonExtractField(cmdObj, "roles", &roles); if (!status.isOK()) { addStatus(Status(ErrorCodes::UserModificationFailed, "Invalid \"roles\" array"), result); return false; } } BSONObjBuilder userObjBuilder; userObjBuilder.append("user", userName); if (cmdObj.hasField("pwd")) { // TODO: hash password once we're receiving plaintext passwords here. userObjBuilder.append("pwd", password); } if (cmdObj.hasField("userSource")) { userObjBuilder.append("userSource", userSource); } if (cmdObj.hasField("readOnly")) { userObjBuilder.append("readOnly", readOnly); } if (cmdObj.hasField("extraData")) { userObjBuilder.append("extraData", extraData); } if (cmdObj.hasField("roles")) { userObjBuilder.append(roles); } status = getGlobalAuthorizationManager()->insertPrivilegeDocument(dbname, userObjBuilder.obj()); if (!status.isOK()) { addStatus(status, result); return false; } return true; }
Status ReadConcernArgs::initialize(const BSONElement& readConcernElem) { invariant(isEmpty()); // only legal to call on uninitialized object. if (readConcernElem.eoo()) { return Status::OK(); } dassert(readConcernElem.fieldNameStringData() == kReadConcernFieldName); if (readConcernElem.type() != Object) { return Status(ErrorCodes::FailedToParse, str::stream() << kReadConcernFieldName << " field should be an object"); } BSONObj readConcernObj = readConcernElem.Obj(); for (auto&& field : readConcernObj) { auto fieldName = field.fieldNameStringData(); if (fieldName == kAfterOpTimeFieldName) { OpTime opTime; // TODO pass field in rather than scanning again. auto opTimeStatus = bsonExtractOpTimeField(readConcernObj, kAfterOpTimeFieldName, &opTime); if (!opTimeStatus.isOK()) { return opTimeStatus; } _opTime = opTime; } else if (fieldName == kAfterClusterTimeFieldName) { Timestamp afterClusterTime; auto afterClusterTimeStatus = bsonExtractTimestampField( readConcernObj, kAfterClusterTimeFieldName, &afterClusterTime); if (!afterClusterTimeStatus.isOK()) { return afterClusterTimeStatus; } _afterClusterTime = LogicalTime(afterClusterTime); } else if (fieldName == kAtClusterTimeFieldName) { Timestamp atClusterTime; auto atClusterTimeStatus = bsonExtractTimestampField(readConcernObj, kAtClusterTimeFieldName, &atClusterTime); if (!atClusterTimeStatus.isOK()) { return atClusterTimeStatus; } _atClusterTime = LogicalTime(atClusterTime); } else if (fieldName == kLevelFieldName) { std::string levelString; // TODO pass field in rather than scanning again. auto readCommittedStatus = bsonExtractStringField(readConcernObj, kLevelFieldName, &levelString); if (!readCommittedStatus.isOK()) { return readCommittedStatus; } if (levelString == kLocalReadConcernStr) { _level = ReadConcernLevel::kLocalReadConcern; } else if (levelString == kMajorityReadConcernStr) { _level = ReadConcernLevel::kMajorityReadConcern; } else if (levelString == kLinearizableReadConcernStr) { _level = ReadConcernLevel::kLinearizableReadConcern; } else if (levelString == kAvailableReadConcernStr) { _level = ReadConcernLevel::kAvailableReadConcern; } else if (levelString == kSnapshotReadConcernStr) { _level = ReadConcernLevel::kSnapshotReadConcern; } else { return Status(ErrorCodes::FailedToParse, str::stream() << kReadConcernFieldName << '.' << kLevelFieldName << " must be either 'local', 'majority', " "'linearizable', 'available', or 'snapshot'"); } _originalLevel = _level; } else { return Status(ErrorCodes::InvalidOptions, str::stream() << "Unrecognized option in " << kReadConcernFieldName << ": " << fieldName); } } if (_afterClusterTime && _opTime) { return Status(ErrorCodes::InvalidOptions, str::stream() << "Can not specify both " << kAfterClusterTimeFieldName << " and " << kAfterOpTimeFieldName); } if (_afterClusterTime && _atClusterTime) { return Status(ErrorCodes::InvalidOptions, str::stream() << "Can not specify both " << kAfterClusterTimeFieldName << " and " << kAtClusterTimeFieldName); } // Note: 'available' should not be used with after cluster time, as cluster time can wait for // replication whereas the premise of 'available' is to avoid waiting. 'linearizable' should not // be used with after cluster time, since linearizable reads are inherently causally consistent. if (_afterClusterTime && getLevel() != ReadConcernLevel::kMajorityReadConcern && getLevel() != ReadConcernLevel::kLocalReadConcern && getLevel() != ReadConcernLevel::kSnapshotReadConcern) { return Status(ErrorCodes::InvalidOptions, str::stream() << kAfterClusterTimeFieldName << " field can be set only if " << kLevelFieldName << " is equal to " << kMajorityReadConcernStr << ", " << kLocalReadConcernStr << ", or " << kSnapshotReadConcernStr); } if (_opTime && getLevel() == ReadConcernLevel::kSnapshotReadConcern) { return Status(ErrorCodes::InvalidOptions, str::stream() << kAfterOpTimeFieldName << " field cannot be set if " << kLevelFieldName << " is equal to " << kSnapshotReadConcernStr); } if (_atClusterTime && getLevel() != ReadConcernLevel::kSnapshotReadConcern) { return Status(ErrorCodes::InvalidOptions, str::stream() << kAtClusterTimeFieldName << " field can be set only if " << kLevelFieldName << " is equal to " << kSnapshotReadConcernStr); } if (_afterClusterTime && _afterClusterTime == LogicalTime::kUninitialized) { return Status(ErrorCodes::InvalidOptions, str::stream() << kAfterClusterTimeFieldName << " cannot be a null timestamp"); } if (_atClusterTime && _atClusterTime == LogicalTime::kUninitialized) { return Status(ErrorCodes::InvalidOptions, str::stream() << kAtClusterTimeFieldName << " cannot be a null timestamp"); } return Status::OK(); }
StatusWith<MoveChunkRequest> MoveChunkRequest::createFromCommand(NamespaceString nss, const BSONObj& obj) { auto secondaryThrottleStatus = MigrationSecondaryThrottleOptions::createFromCommand(obj); if (!secondaryThrottleStatus.isOK()) { return secondaryThrottleStatus.getStatus(); } MoveChunkRequest request(std::move(nss), std::move(secondaryThrottleStatus.getValue())); { std::string configServerConnectionString; Status status = bsonExtractStringField( obj, kConfigServerConnectionString, &configServerConnectionString); if (!status.isOK()) { return status; } auto statusConfigServerCS = ConnectionString::parse(configServerConnectionString); if (!statusConfigServerCS.isOK()) { return statusConfigServerCS.getStatus(); } request._configServerCS = std::move(statusConfigServerCS.getValue()); } { Status status = bsonExtractStringField(obj, kFromShardId, &request._fromShardId); if (!status.isOK()) { return status; } } { Status status = bsonExtractStringField(obj, kToShardId, &request._toShardId); if (!status.isOK()) { return status; } } { BSONElement elem; Status status = bsonExtractTypedField(obj, kChunkMinKey, BSONType::Object, &elem); if (!status.isOK()) { return status; } request._minKey = elem.Obj().getOwned(); if (request._minKey.isEmpty()) { return Status(ErrorCodes::UnsupportedFormat, "The chunk min key cannot be empty"); } } { BSONElement elem; Status status = bsonExtractTypedField(obj, kChunkMaxKey, BSONType::Object, &elem); if (!status.isOK()) { return status; } request._maxKey = elem.Obj().getOwned(); if (request._maxKey.isEmpty()) { return Status(ErrorCodes::UnsupportedFormat, "The chunk max key cannot be empty"); } } { Status status = bsonExtractBooleanFieldWithDefault(obj, kWaitForDelete, 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); } return request; }
Status parseAndValidateCreateRoleCommand(const BSONObj& cmdObj, const std::string& dbname, AuthorizationManager* authzManager, BSONObj* parsedRoleObj, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert("createRole"); validFieldNames.insert("privileges"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "createRole", validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } BSONObjBuilder roleObjBuilder; // Parse role name std::string roleName; status = bsonExtractStringField(cmdObj, "createRole", &roleName); if (!status.isOK()) { return status; } // Prevent creating roles in the local database if (dbname == "local") { return Status(ErrorCodes::BadValue, "Cannot create roles in the local database"); } roleObjBuilder.append("_id", dbname + "." + roleName); roleObjBuilder.append(AuthorizationManager::ROLE_NAME_FIELD_NAME, roleName); roleObjBuilder.append(AuthorizationManager::ROLE_SOURCE_FIELD_NAME, dbname); // Parse privileges BSONElement privilegesElement; status = bsonExtractTypedField(cmdObj, "privileges", Array, &privilegesElement); if (!status.isOK()) { return status; } status = _parseAndValidatePrivilegeArray(BSONArray(privilegesElement.Obj()), NULL); if (!status.isOK()) { return status; } roleObjBuilder.append(privilegesElement); // Parse roles BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } BSONArray modifiedRolesArray; status = _validateAndModifyRolesArray(rolesElement, dbname, authzManager, false, &modifiedRolesArray); if (!status.isOK()) { return status; } roleObjBuilder.append("roles", modifiedRolesArray); *parsedRoleObj = roleObjBuilder.obj(); return Status::OK(); }
StatusWith<SetShardVersionRequest> SetShardVersionRequest::parseFromBSON(const BSONObj& cmdObj) { SetShardVersionRequest request; { std::string configServer; Status status = bsonExtractStringField(cmdObj, kConfigServer, &configServer); if (!status.isOK()) return status; auto configServerStatus = ConnectionString::parse(configServer); if (!configServerStatus.isOK()) return configServerStatus.getStatus(); request._configServer = std::move(configServerStatus.getValue()); } { Status status = bsonExtractStringField(cmdObj, kShardName, &request._shardName); if (!status.isOK()) return status; } { std::string shardCS; Status status = bsonExtractStringField(cmdObj, kShardConnectionString, &shardCS); if (!status.isOK()) return status; auto shardCSStatus = ConnectionString::parse(shardCS); if (!shardCSStatus.isOK()) return shardCSStatus.getStatus(); request._shardCS = std::move(shardCSStatus.getValue()); } { Status status = bsonExtractBooleanFieldWithDefault(cmdObj, kInit, false, &request._init); if (!status.isOK()) return status; } { Status status = bsonExtractBooleanFieldWithDefault( cmdObj, kAuthoritative, false, &request._isAuthoritative); if (!status.isOK()) return status; } { Status status = bsonExtractBooleanFieldWithDefault( cmdObj, kNoConnectionVersioning, false, &request._noConnectionVersioning); if (!status.isOK()) return status; } if (request.isInit()) { return request; } // Only initialize the version information if this is not an "init" request { std::string ns; Status status = bsonExtractStringField(cmdObj, kCmdName, &ns); if (!status.isOK()) return status; NamespaceString nss(ns); if (!nss.isValid()) { return {ErrorCodes::InvalidNamespace, str::stream() << ns << " is not a valid namespace"}; } request._nss = std::move(nss); } { auto versionStatus = ChunkVersionAndOpTime::parseFromBSONForSetShardVersion(cmdObj); if (!versionStatus.isOK()) return versionStatus.getStatus(); request._version = versionStatus.getValue(); } return request; }
Status parseAndValidateCreateUserCommand(const BSONObj& cmdObj, const std::string& dbname, AuthorizationManager* authzManager, BSONObj* parsedUserObj, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert("createUser"); validFieldNames.insert("customData"); validFieldNames.insert("pwd"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "createUser", validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } BSONObjBuilder userObjBuilder; // Parse user name std::string userName; status = bsonExtractStringField(cmdObj, "createUser", &userName); if (!status.isOK()) { return status; } // Prevent creating users in the local database if (dbname == "local") { return Status(ErrorCodes::BadValue, "Cannot create users in the local database"); } userObjBuilder.append("_id", dbname + "." + userName); userObjBuilder.append(AuthorizationManager::USER_NAME_FIELD_NAME, userName); userObjBuilder.append(AuthorizationManager::USER_SOURCE_FIELD_NAME, dbname); // Parse password if (cmdObj.hasField("pwd")) { std::string clearTextPassword; status = bsonExtractStringField(cmdObj, "pwd", &clearTextPassword); if (!status.isOK()) { return status; } std::string password = auth::createPasswordDigest(userName, clearTextPassword); userObjBuilder.append("credentials", BSON("MONGODB-CR" << password)); } else { if (dbname != "$external") { return Status(ErrorCodes::BadValue, "Must provide a 'pwd' field for all user documents, except those" " with '$external' as the user's source"); } } // Parse custom data if (cmdObj.hasField("customData")) { BSONElement element; status = bsonExtractTypedField(cmdObj, "customData", Object, &element); if (!status.isOK()) { return status; } userObjBuilder.append("customData", element.Obj()); } // Parse roles if (cmdObj.hasField("roles")) { BSONElement rolesElement; status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } BSONArray modifiedRolesArray; status = _validateAndModifyRolesArray(rolesElement, dbname, authzManager, true, &modifiedRolesArray); if (!status.isOK()) { return status; } userObjBuilder.append("roles", modifiedRolesArray); } *parsedUserObj = userObjBuilder.obj(); // Make sure document to insert is valid V2UserDocumentParser parser; status = parser.checkValidUserDocument(*parsedUserObj); if (!status.isOK()) { return status; } return Status::OK(); }
Status MemberConfig::initialize(const BSONObj& mcfg, ReplicaSetTagConfig* tagConfig) { Status status = bsonCheckOnlyHasFields( "replica set member configuration", mcfg, kLegalMemberConfigFieldNames); if (!status.isOK()) return status; // // Parse _id field. // BSONElement idElement = mcfg[kIdFieldName]; if (idElement.eoo()) { return Status(ErrorCodes::NoSuchKey, str::stream() << kIdFieldName << " field is missing"); } if (!idElement.isNumber()) { return Status(ErrorCodes::TypeMismatch, str::stream() << kIdFieldName << " field has non-numeric type " << typeName(idElement.type())); } _id = idElement.numberInt(); // // Parse h field. // std::string hostAndPortString; status = bsonExtractStringField(mcfg, kHostFieldName, &hostAndPortString); if (!status.isOK()) return status; boost::trim(hostAndPortString); status = _host.initialize(hostAndPortString); if (!status.isOK()) return status; if (!_host.hasPort()) { // make port explicit even if default. _host = HostAndPort(_host.host(), _host.port()); } // // Parse votes field. // BSONElement votesElement = mcfg[kVotesFieldName]; int votes; if (votesElement.eoo()) { votes = kVotesFieldDefault; } else if (votesElement.isNumber()) { votes = votesElement.numberInt(); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << kVotesFieldName << " field value has non-numeric type " << typeName(votesElement.type())); } if (votes != 0 && votes != 1) { return Status(ErrorCodes::BadValue, str::stream() << kVotesFieldName << " field value is " << votesElement.numberInt() << " but must be 0 or 1"); } _isVoter = bool(votes); // // Parse priority field. // BSONElement priorityElement = mcfg[kPriorityFieldName]; if (priorityElement.eoo()) { _priority = kPriorityFieldDefault; } else if (priorityElement.isNumber()) { _priority = priorityElement.numberDouble(); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << kPriorityFieldName << " field has non-numeric type " << typeName(priorityElement.type())); } // // Parse arbiterOnly field. // status = bsonExtractBooleanFieldWithDefault(mcfg, kArbiterOnlyFieldName, kArbiterOnlyFieldDefault, &_arbiterOnly); if (!status.isOK()) return status; // // Parse slaveDelay field. // BSONElement slaveDelayElement = mcfg[kSlaveDelayFieldName]; if (slaveDelayElement.eoo()) { _slaveDelay = kSlaveDelayFieldDefault; } else if (slaveDelayElement.isNumber()) { _slaveDelay = Seconds(slaveDelayElement.numberInt()); } else { return Status(ErrorCodes::TypeMismatch, str::stream() << kSlaveDelayFieldName << " field value has non-numeric type " << typeName(slaveDelayElement.type())); } // // Parse hidden field. // status = bsonExtractBooleanFieldWithDefault(mcfg, kHiddenFieldName, kHiddenFieldDefault, &_hidden); if (!status.isOK()) return status; // // Parse buildIndexes field. // status = bsonExtractBooleanFieldWithDefault(mcfg, kBuildIndexesFieldName, kBuildIndexesFieldDefault, &_buildIndexes); if (!status.isOK()) return status; // // Parse "tags" field. // _tags.clear(); BSONElement tagsElement; status = bsonExtractTypedField(mcfg, kTagsFieldName, Object, &tagsElement); if (status.isOK()) { for (BSONObj::iterator tagIter(tagsElement.Obj()); tagIter.more();) { const BSONElement& tag = tagIter.next(); if (tag.type() != String) { return Status(ErrorCodes::TypeMismatch, str::stream() << "tags." << tag.fieldName() << " field has non-string value of type " << typeName(tag.type())); } _tags.push_back(tagConfig->makeTag(tag.fieldNameStringData(), tag.valueStringData())); } } else if (ErrorCodes::NoSuchKey != status) { return status; } return Status::OK(); }
Status parseAndValidateUpdateUserCommand(const BSONObj& cmdObj, const std::string& dbname, AuthorizationManager* authzManager, BSONObj* parsedUpdateObj, UserName* parsedUserName, BSONObj* parsedWriteConcern) { unordered_set<std::string> validFieldNames; validFieldNames.insert("updateUser"); validFieldNames.insert("customData"); validFieldNames.insert("pwd"); validFieldNames.insert("roles"); validFieldNames.insert("writeConcern"); Status status = _checkNoExtraFields(cmdObj, "updateUser", validFieldNames); if (!status.isOK()) { return status; } status = _extractWriteConcern(cmdObj, parsedWriteConcern); if (!status.isOK()) { return status; } BSONObjBuilder updateSetBuilder; // Parse user name std::string userName; status = bsonExtractStringField(cmdObj, "updateUser", &userName); if (!status.isOK()) { return status; } *parsedUserName = UserName(userName, dbname); // Parse password if (cmdObj.hasField("pwd")) { std::string clearTextPassword; status = bsonExtractStringField(cmdObj, "pwd", &clearTextPassword); if (!status.isOK()) { return status; } std::string password = auth::createPasswordDigest(userName, clearTextPassword); updateSetBuilder.append("credentials.MONGODB-CR", password); } // Parse custom data if (cmdObj.hasField("customData")) { BSONElement element; status = bsonExtractTypedField(cmdObj, "customData", Object, &element); if (!status.isOK()) { return status; } updateSetBuilder.append("customData", element.Obj()); } // Parse roles if (cmdObj.hasField("roles")) { BSONElement rolesElement; Status status = bsonExtractTypedField(cmdObj, "roles", Array, &rolesElement); if (!status.isOK()) { return status; } BSONArray modifiedRolesObj; status = _validateAndModifyRolesArray(rolesElement, dbname, authzManager, true, &modifiedRolesObj); if (!status.isOK()) { return status; } updateSetBuilder.append("roles", modifiedRolesObj); } BSONObj updateSet = updateSetBuilder.obj(); if (updateSet.isEmpty()) { return Status(ErrorCodes::UserModificationFailed, "Must specify at least one field to update in updateUser"); } *parsedUpdateObj = BSON("$set" << updateSet); return Status::OK(); }
StatusWith<StartChunkCloneRequest> StartChunkCloneRequest::createFromCommand(NamespaceString nss, const BSONObj& obj) { auto secondaryThrottleStatus = MigrationSecondaryThrottleOptions::createFromCommand(obj); if (!secondaryThrottleStatus.isOK()) { return secondaryThrottleStatus.getStatus(); } auto sessionIdStatus = MigrationSessionId::extractFromBSON(obj); if (!sessionIdStatus.isOK()) { return sessionIdStatus.getStatus(); } StartChunkCloneRequest request(std::move(nss), std::move(sessionIdStatus.getValue()), std::move(secondaryThrottleStatus.getValue())); { std::string configServerConnectionString; Status status = bsonExtractStringField( obj, kConfigServerConnectionString, &configServerConnectionString); if (!status.isOK()) { return status; } auto statusConfigServerCS = ConnectionString::parse(configServerConnectionString); if (!statusConfigServerCS.isOK()) { return statusConfigServerCS.getStatus(); } request._configServerCS = std::move(statusConfigServerCS.getValue()); } { std::string fromShardConnectionString; Status status = bsonExtractStringField(obj, kFromShardConnectionString, &fromShardConnectionString); if (!status.isOK()) { return status; } auto fromShardConnectionStringStatus = ConnectionString::parse(fromShardConnectionString); if (!fromShardConnectionStringStatus.isOK()) { return fromShardConnectionStringStatus.getStatus(); } request._fromShardCS = std::move(fromShardConnectionStringStatus.getValue()); } { std::string fromShard; Status status = bsonExtractStringField(obj, kFromShardId, &fromShard); request._fromShardId = fromShard; if (!status.isOK()) { return status; } } { std::string toShard; Status status = bsonExtractStringField(obj, kToShardId, &toShard); request._toShardId = toShard; if (!status.isOK()) { return status; } } { BSONElement elem; Status status = bsonExtractTypedField(obj, kChunkMinKey, BSONType::Object, &elem); if (!status.isOK()) { return status; } request._minKey = elem.Obj().getOwned(); if (request._minKey.isEmpty()) { return Status(ErrorCodes::UnsupportedFormat, "The chunk min key cannot be empty"); } } { BSONElement elem; Status status = bsonExtractTypedField(obj, kChunkMaxKey, BSONType::Object, &elem); if (!status.isOK()) { return status; } request._maxKey = elem.Obj().getOwned(); if (request._maxKey.isEmpty()) { return Status(ErrorCodes::UnsupportedFormat, "The chunk max key cannot be empty"); } } { BSONElement elem; Status status = bsonExtractTypedField(obj, kShardKeyPattern, BSONType::Object, &elem); if (!status.isOK()) { return status; } request._shardKeyPattern = elem.Obj().getOwned(); if (request._shardKeyPattern.isEmpty()) { return Status(ErrorCodes::UnsupportedFormat, "The shard key pattern cannot be empty"); } } return request; }
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 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(); }