bool run(OperationContext* opCtx,
             const string& dbname,
             const BSONObj& cmdObj,
             BSONObjBuilder& result) {
        auth::CreateOrUpdateRoleArgs args;
        Status status = auth::parseCreateOrUpdateRoleCommands(cmdObj, "createRole", dbname, &args);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        if (args.roleName.getRole().empty()) {
            return appendCommandStatus(result,
                                       Status(ErrorCodes::BadValue, "Role name must be non-empty"));
        }

        if (args.roleName.getDB() == "local") {
            return appendCommandStatus(
                result, Status(ErrorCodes::BadValue, "Cannot create roles in the local database"));
        }

        if (args.roleName.getDB() == "$external") {
            return appendCommandStatus(
                result,
                Status(ErrorCodes::BadValue, "Cannot create roles in the $external database"));
        }

        if (RoleGraph::isBuiltinRole(args.roleName)) {
            return appendCommandStatus(
                result,
                Status(ErrorCodes::BadValue,
                       "Cannot create roles with the same name as a built-in role"));
        }

        if (!args.hasRoles) {
            return appendCommandStatus(
                result,
                Status(ErrorCodes::BadValue, "\"createRole\" command requires a \"roles\" array"));
        }

        if (!args.hasPrivileges) {
            return appendCommandStatus(
                result,
                Status(ErrorCodes::BadValue,
                       "\"createRole\" command requires a \"privileges\" array"));
        }

        BSONObjBuilder roleObjBuilder;

        roleObjBuilder.append(
            "_id", str::stream() << args.roleName.getDB() << "." << args.roleName.getRole());
        roleObjBuilder.append(AuthorizationManager::ROLE_NAME_FIELD_NAME, args.roleName.getRole());
        roleObjBuilder.append(AuthorizationManager::ROLE_DB_FIELD_NAME, args.roleName.getDB());

        BSONArray privileges;
        status = privilegeVectorToBSONArray(args.privileges, &privileges);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }
        roleObjBuilder.append("privileges", privileges);

        roleObjBuilder.append("roles", rolesVectorToBSONArray(args.roles));

        if (args.authenticationRestrictions && !args.authenticationRestrictions->isEmpty()) {
            roleObjBuilder.append("authenticationRestrictions",
                                  args.authenticationRestrictions.get());
        }

        ServiceContext* serviceContext = opCtx->getClient()->getServiceContext();
        stdx::lock_guard<stdx::mutex> lk(getAuthzDataMutex(serviceContext));

        AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);
        status = requireAuthSchemaVersion26Final(opCtx, authzManager);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        // Role existence has to be checked after acquiring the update lock
        status = checkOkayToGrantRolesToRole(opCtx, args.roleName, args.roles, authzManager);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        status = checkOkayToGrantPrivilegesToRole(args.roleName, args.privileges);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        audit::logCreateRole(Client::getCurrent(),
                             args.roleName,
                             args.roles,
                             args.privileges,
                             args.authenticationRestrictions);

        status = insertRoleDocument(opCtx, roleObjBuilder.done());
        return appendCommandStatus(result, status);
    }