    bool run(OperationContext* opCtx,
             const string& dbname,
             const BSONObj& cmdObj,
             BSONObjBuilder& result) {
        std::string roleNameString;
        std::vector<RoleName> rolesToAdd;
        Status status = auth::parseRolePossessionManipulationCommands(
            cmdObj, "grantRolesToRole", dbname, &roleNameString, &rolesToAdd);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        RoleName roleName(roleNameString, dbname);
        if (RoleGraph::isBuiltinRole(roleName)) {
            return appendCommandStatus(
                result,
                Status(ErrorCodes::InvalidRoleModification,
                       str::stream() << roleName.getFullName()
                                     << " is a built-in role and cannot be modified."));
        }

        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
        BSONObj roleDoc;
        status = authzManager->getRoleDescription(opCtx, roleName, &roleDoc);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        // Check for cycles
        status = checkOkayToGrantRolesToRole(opCtx, roleName, rolesToAdd, authzManager);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        // Add new roles to existing roles
        std::vector<RoleName> directRoles;
        status = auth::parseRoleNamesFromBSONArray(
            BSONArray(roleDoc["roles"].Obj()), roleName.getDB(), &directRoles);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }
        for (vector<RoleName>::iterator it = rolesToAdd.begin(); it != rolesToAdd.end(); ++it) {
            const RoleName& roleToAdd = *it;
            if (!sequenceContains(directRoles, roleToAdd))  // Don't double-add role
                directRoles.push_back(*it);
        }

        audit::logGrantRolesToRole(Client::getCurrent(), roleName, rolesToAdd);

        status = updateRoleDocument(
            opCtx, roleName, BSON("$set" << BSON("roles" << rolesVectorToBSONArray(directRoles))));
        // Must invalidate even on bad status - what if the write succeeded but the GLE failed?
        authzManager->invalidateUserCache();
        return appendCommandStatus(result, status);
    }
    bool run(OperationContext* opCtx,
             const string& dbname,
             const BSONObj& cmdObj,
             BSONObjBuilder& result) {
        std::string roleNameString;
        std::vector<RoleName> rolesToAdd;
        Status status = auth::parseRolePossessionManipulationCommands(
            cmdObj, "grantRolesToRole", dbname, &roleNameString, &rolesToAdd);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

        RoleName roleName(roleNameString, dbname);
        if (RoleGraph::isBuiltinRole(roleName)) {
            return appendCommandStatus(
                result,
                Status(ErrorCodes::InvalidRoleModification,
                       str::stream() << roleName.getFullName()
                                     << " is a built-in role and cannot be modified."));
        }

        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);
        }

         
        BSONObj roleDoc;
        status = authzManager->getRoleDescription(opCtx, roleName, &roleDoc);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

         
        status = checkOkayToGrantRolesToRole(opCtx, roleName, rolesToAdd, authzManager);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }

         
        std::vector<RoleName> directRoles;
        status = auth::parseRoleNamesFromBSONArray(
            BSONArray(roleDoc["roles"].Obj()), roleName.getDB(), &directRoles);
        if (!status.isOK()) {
            return appendCommandStatus(result, status);
        }
        for (vector<RoleName>::iterator it = rolesToAdd.begin(); it != rolesToAdd.end(); ++it) {
            const RoleName& roleToAdd = *it;
            if (!sequenceContains(directRoles, roleToAdd))   
                directRoles.push_back(*it);
        }

        audit::logGrantRolesToRole(Client::getCurrent(), roleName, rolesToAdd);

        status = updateRoleDocument(
            opCtx, roleName, BSON("$set" << BSON("roles" << rolesVectorToBSONArray(directRoles))));
         
        authzManager->invalidateUserCache();
        return appendCommandStatus(result, status);
    }