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));
}
예제 #2
0
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();
}
예제 #3
0
 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();
 }
예제 #4
0
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;
}
예제 #5
0
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();
    }
}
예제 #6
0
 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();
 }
예제 #7
0
        // 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;
        }