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 bsonExtractDoubleField(const BSONObj& object, StringData fieldName, double* out) { BSONElement value; Status status = bsonExtractField(object, fieldName, &value); if (!status.isOK()) return status; if (!value.isNumber()) { return Status(ErrorCodes::TypeMismatch, mongoutils::str::stream() << "Expected field \"" << fieldName << "\" to have numeric type, but found " << typeName(value.type())); } *out = value.numberDouble(); return Status::OK(); }
Status bsonExtractTypedField(const BSONObj& object, const StringData& fieldName, BSONType type, BSONElement* outElement) { Status status = bsonExtractField(object, fieldName, outElement); if (!status.isOK()) return status; if (type != outElement->type()) { return Status(ErrorCodes::TypeMismatch, mongoutils::str::stream() << "\"" << fieldName << "\" had the wrong type. Expected " << typeName(type) << ", found " << typeName(outElement->type())); } return Status::OK(); }
StatusWith<ChunkVersion> ChunkVersion::parseFromBSONWithFieldForCommands(const BSONObj& obj, StringData field) { BSONElement versionElem; Status status = bsonExtractField(obj, field, &versionElem); if (!status.isOK()) return status; if (versionElem.type() != Array) { return {ErrorCodes::TypeMismatch, str::stream() << "Invalid type " << versionElem.type() << " for shardVersion element. Expected an array"}; } BSONObjIterator it(versionElem.Obj()); if (!it.more()) return {ErrorCodes::BadValue, "Unexpected empty version"}; ChunkVersion version; // Expect the timestamp { BSONElement tsPart = it.next(); if (tsPart.type() != bsonTimestamp) return {ErrorCodes::TypeMismatch, str::stream() << "Invalid type " << tsPart.type() << " for version timestamp part."}; version._combined = tsPart.timestamp().asULL(); } // Expect the epoch OID { BSONElement epochPart = it.next(); if (epochPart.type() != jstOID) return {ErrorCodes::TypeMismatch, str::stream() << "Invalid type " << epochPart.type() << " for version epoch part."}; version._epoch = epochPart.OID(); } return version; }
Status bsonExtractBooleanFieldWithDefault(const BSONObj& object, StringData fieldName, bool defaultValue, bool* out) { BSONElement value; Status status = bsonExtractField(object, fieldName, &value); if (status == ErrorCodes::NoSuchKey) { *out = defaultValue; return Status::OK(); } else if (!status.isOK()) { return status; } else if (!value.isNumber() && !value.isBoolean()) { return Status(ErrorCodes::TypeMismatch, mongoutils::str::stream() << "Expected boolean or number type for field \"" << fieldName << "\", found " << typeName(value.type())); } else { *out = value.trueValue(); return Status::OK(); } }
Status bsonExtractIntegerField(const BSONObj& object, const StringData& fieldName, long long* out) { BSONElement value; Status status = bsonExtractField(object, fieldName, &value); if (!status.isOK()) return status; if (!value.isNumber()) { return Status(ErrorCodes::TypeMismatch, mongoutils::str::stream() << "Expected field \"" << fieldName << "\" to have numeric type, but found " << typeName(value.type())); } long long result = value.safeNumberLong(); if (result != value.numberDouble()) { return Status(ErrorCodes::BadValue, mongoutils::str::stream() << "Expected field \"" << fieldName << "\" to have a value " "exactly representable as a 64-bit integer, but found " << value); } *out = result; return Status::OK(); }
// 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; }