bool run(OperationContext* opCtx,
             const string& dbname,
             const BSONObj& cmdObj,
             BSONObjBuilder& result) {
        auth::CreateOrUpdateRoleArgs args;
        Status status = auth::parseCreateOrUpdateRoleCommands(cmdObj, "updateRole", dbname, &args);
        uassertStatusOK(status);

        if (!args.hasPrivileges && !args.hasRoles && !args.authenticationRestrictions) {
            uasserted(ErrorCodes::BadValue,
                      "Must specify at least one field to update in updateRole");
        }

        BSONObjBuilder updateSetBuilder;
        BSONObjBuilder updateUnsetBuilder;

        if (args.hasPrivileges) {
            BSONArray privileges;
            status = privilegeVectorToBSONArray(args.privileges, &privileges);
            uassertStatusOK(status);
            updateSetBuilder.append("privileges", privileges);
        }

        if (args.hasRoles) {
            updateSetBuilder.append("roles", rolesVectorToBSONArray(args.roles));
        }

        if (args.authenticationRestrictions) {
            if (args.authenticationRestrictions->isEmpty()) {
                updateUnsetBuilder.append("authenticationRestrictions", "");
            } else {
                updateSetBuilder.append("authenticationRestrictions",
                                        args.authenticationRestrictions.get());
            }
        }

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

        AuthorizationManager* authzManager = AuthorizationManager::get(serviceContext);
        status = requireWritableAuthSchema28SCRAM(opCtx, authzManager);
        uassertStatusOK(status);

        // Role existence has to be checked after acquiring the update lock
        BSONObj ignored;
        status = authzManager->getRoleDescription(opCtx, args.roleName, &ignored);
        uassertStatusOK(status);

        if (args.hasRoles) {
            status = checkOkayToGrantRolesToRole(opCtx, args.roleName, args.roles, authzManager);
            uassertStatusOK(status);
        }

        if (args.hasPrivileges) {
            status = checkOkayToGrantPrivilegesToRole(args.roleName, args.privileges);
            uassertStatusOK(status);
        }

        audit::logUpdateRole(Client::getCurrent(),
                             args.roleName,
                             args.hasRoles ? &args.roles : nullptr,
                             args.hasPrivileges ? &args.privileges : nullptr,
                             args.authenticationRestrictions);

        const auto updateSet = updateSetBuilder.obj();
        const auto updateUnset = updateUnsetBuilder.obj();
        BSONObjBuilder updateDocumentBuilder;
        if (!updateSet.isEmpty()) {
            updateDocumentBuilder.append("$set", updateSet);
        }
        if (!updateUnset.isEmpty()) {
            updateDocumentBuilder.append("$unset", updateUnset);
        }

        status = updateRoleDocument(opCtx, args.roleName, updateDocumentBuilder.obj());
        // Must invalidate even on bad status - what if the write succeeded but the GLE failed?
        authzManager->invalidateUserCache();
        uassertStatusOK(status);
        return true;
    }