def dependency_pending(dep_id, local_db=db, local_co=const):
    if not dep_id:
        return False
    br = BofhdRequests(local_db, local_co)
    for dr in br.get_requests(request_id=dep_id):
        logger.debug("waiting for request %d" % int(dep_id))
        return True
    return False
Exemplo n.º 2
0
 def read_pending_moves(self):
     br = BofhdRequests(self._db, self.const)
     # We define near future as 15 minutes from now.
     near_future = mx.DateTime.now() + mx.DateTime.DateTimeDelta(0, 0, 15)
     for op in (self.const.bofh_email_create,
                self.const.bofh_email_convert):
         for r in br.get_requests(operation=op):
             if r['run_at'] < near_future:
                 self.pending[int(r['entity_id'])] = True
 def can_cancel_request(self, operator, req_id, query_run_any=False):
     if query_run_any:
         return True
     if self.is_superuser(operator):
         return True
     br = BofhdRequests(self._db, self.const)
     for r in br.get_requests(request_id=req_id):
         if r['requestee_id'] and int(r['requestee_id']) == operator:
             return True
     raise PermissionDenied("You are not requester")
 def misc_list_bofhd_request_types(self, operator):
     br = BofhdRequests(self.db, self.const)
     result = []
     for row in br.get_operations():
         br_code = self.const.BofhdRequestOp(row['code_str'])
         result.append({
             'code_str': six.text_type(br_code).lstrip('br_'),
             'description': br_code.description,
         })
     return result
 def misc_cancel_request(self, operator, req):
     if req.isdigit():
         req_id = int(req)
     else:
         raise CerebrumError("Request-ID must be a number")
     br = BofhdRequests(self.db, self.const)
     if not br.get_requests(request_id=req_id):
         raise CerebrumError("Request ID %d not found" % req_id)
     self.ba.can_cancel_request(operator.get_entity_id(), req_id)
     br.delete_request(request_id=req_id)
     return "OK, %d canceled" % req_id
Exemplo n.º 6
0
    def release_guest(self, guest, operator_id):
        """Release a guest account from temporary owner.

        Make sure that the guest account specified actually exists and
        release it from owner. The guest account is now in
        release_quarantine and will be available for new allocations
        when the quarantine period is due.

        @param guest: uname of guest account
        @type guest: str

        @param operator_id: entity id of operator
        @type operator_id: int
        """
        ac = Factory.get('Account')(self.db)
        ac.find_by_name(guest)
        trait = ac.get_trait(self.co.trait_uio_guest_owner)
        if trait is None:
            raise GuestAccountException("%s is not a guest" % guest)
        elif trait['target_id'] is None:
            raise GuestAccountException("%s is already available" % guest)
        # Clear the password so that the account can't be used
        ac.delete_password()  # delete_password() writes its changes directly
        # Remove owner, i.e set owner_trait to None
        ac.populate_trait(self.co.trait_uio_guest_owner, target_id=None)
        self.logger.debug("Removed owner_id in owner_trait for %s" % guest)
        # Remove quarantine set by _alloc_guest and set a new
        # quarantine that kicks in now.
        if ac.get_entity_quarantine(self.co.quarantine_guest_release):
            ac.delete_entity_quarantine(self.co.quarantine_guest_release)
        ac.add_entity_quarantine(self.co.quarantine_guest_release,
                                 operator_id,
                                 "Guest user released",
                                 start=DateTime.today())
        self.logger.debug("%s is now in release_quarantine" % guest)
        ac.write_db()
        self.update_group_memberships(ac.entity_id)
        self.logger.debug("Updating group memberships for %s" % guest)
        # Finally, register a request to archive the home directory.
        # A new directory will be created when archival has been done.
        br = BofhdRequests(self.db, self.co)
        br.add_request(operator_id,
                       br.now,
                       self.co.bofh_archive_user,
                       ac.entity_id,
                       None,
                       state_data=int(self.co.spread_uio_nis_user))
        self.logger.debug("Added archive_user request for %s" % guest)
Exemplo n.º 7
0
def process_account(account, delete=False, bofhdreq=False):
    """Deactivate the given account.

    :param Cerebrum.Account: The account that should get deactivated.

    :param bool delete:
        If True, the account will be totally deleted instead of just
        deactivated.

    :param bool bofhdreq:
        If True, the account will be given to BofhdRequest for further
        processing. It will then not be deactivated by this script.

    :rtype: bool
    :returns: If the account really got deactivated/deleted.

    """
    if account.is_deleted():
        logger.debug2("Account %s already deleted", account.account_name)
        return False
    logger.info('Deactivating account: %s (%s)', account.account_name,
                account.entity_id)
    if delete:
        logger.info("Terminating account: %s", account.account_name)
        account.terminate()
    elif bofhdreq:
        logger.debug("Send to BofhdRequest: %s", account.account_name)
        br = BofhdRequests(database, constants)
        try:
            reqid = br.add_request(operator_id,
                                   when=br.now,
                                   op_code=constants.bofh_delete_user,
                                   entity_id=account.entity_id,
                                   destination_id=None)
            logger.debug("BofhdRequest-Id: %s", reqid)
        except Errors.CerebrumError as e:
            # A CerebrumError is thrown if there exists some move_user for the
            # same user...
            logger.warn("Couldn't delete %s: %s", account.account_name, e)
            return False
    else:
        account.deactivate()
    return True
Exemplo n.º 8
0
 def __init__(self,
              db,
              co,
              ou_perspective,
              emne_info_file,
              studconfig_file,
              studieprogs_file,
              default_spread=None):
     self.db = db
     self.co = co
     self.br = BofhdRequests(self.db, self.co)
     self.default_spread = default_spread
     logger.debug("Preparing autostud framework")
     self.autostud = AutoStud.AutoStud(self.db,
                                       logger.getChild('autostud'),
                                       debug=False,
                                       cfg_file=studconfig_file,
                                       studieprogs_file=studieprogs_file,
                                       emne_info_file=emne_info_file,
                                       ou_perspective=ou_perspective)
Exemplo n.º 9
0
def _set_user_disk(account_id, user, current_disk_id, disk_spread, new_disk):
    if current_disk_id is None:
        logger.debug("Set home: %s", new_disk)
        homedir_id = user.set_homedir(disk_id=new_disk,
                                      status=const.home_status_not_created)
        user.set_home(disk_spread, homedir_id)
        accounts[account_id].set_home(disk_spread, new_disk, homedir_id)
    else:
        br = BofhdRequests(db, const)
        # TBD: Is it correct to set requestee_id=None?
        try:
            br.add_request(None,
                           br.batch_time,
                           const.bofh_move_user,
                           account_id,
                           new_disk,
                           state_data=int(disk_spread))
        except errors.CerebrumError as e:
            # Conflicting request or similiar
            logger.warn(e)
Exemplo n.º 10
0
 def _UiO_order_cyrus_action(self, action, destination, state_data=None):
     br = BofhdRequests(self._db, self.const)
     # If there are any registered BofhdRequests for this account
     # that would conflict with 'action', remove them.
     for anti_action in br.get_conflicts(action):
         for r in br.get_requests(entity_id=self.entity_id,
                                  operation=anti_action):
             self.logger.info("Removing BofhdRequest #%d: %r",
                              r['request_id'], r)
             br.delete_request(request_id=r['request_id'])
     # If the ChangeLog module knows who the user requesting this
     # change is, use that knowledge.  Otherwise, set requestor to
     # None; it's the best we can do.
     requestor = getattr(self._db, 'change_by', None)
     # Register a BofhdRequest to create the mailbox.
     br.add_request(requestor,
                    br.now,
                    action,
                    self.entity_id,
                    destination,
                    state_data=state_data)
Exemplo n.º 11
0
 def misc_change_request(self, operator, request_id, datetime):
     if not request_id:
         raise CerebrumError('Request id required')
     if not datetime:
         raise CerebrumError('Date required')
     datetime = self._parse_date(datetime)
     br = BofhdRequests(self.db, self.const)
     old_req = br.get_requests(request_id=request_id)
     if not old_req:
         raise CerebrumError("There is no request with id=%r" % request_id)
     else:
         # If there is anything, it's at most one
         old_req = old_req[0]
     # If you are allowed to cancel a request, you can change it :)
     self.ba.can_cancel_request(operator.get_entity_id(), request_id)
     br.delete_request(request_id=request_id)
     br.add_request(operator.get_entity_id(), datetime,
                    old_req['operation'], old_req['entity_id'],
                    old_req['destination_id'], old_req['state_data'])
     return "OK, altered request %s" % request_id
Exemplo n.º 12
0
 def process_requests(self, operations_map, op_types, max_requests):
     with closing(RequestLockHandler()) as reqlock:
         br = BofhdRequests(self.db, self.co)
         for t in op_types:
             for op in self.op_type_map[t]:
                 if op not in operations_map:
                     logger.info('Unable to process operation %r', op)
                     continue
                 func, settings = operations_map[op]
                 delay = settings.get('delay', 0)
                 set_operator(self.db)
                 start_time = time.time()
                 for r in br.get_requests(operation=op, only_runnable=True):
                     reqid = r['request_id']
                     logger.debug("Req: %s %d at %s, state %r", op, reqid,
                                  r['run_at'], r['state_data'])
                     if time.time() - start_time > 30 * 60:
                         break
                     if r['run_at'] > mx.DateTime.now():
                         continue
                     # Moving users only at ok times
                     if (op is self.co.bofh_move_user
                             and not is_ok_batch_time()):
                         break
                     if not is_valid_request(br, reqid):
                         continue
                     if reqlock.grab(reqid):
                         if max_requests <= 0:
                             break
                         max_requests -= 1
                         if func(r):
                             br.delete_request(request_id=reqid)
                             self.db.commit()
                         else:
                             self.db.rollback()
                             if delay:
                                 br.delay_request(reqid, minutes=delay)
                                 self.db.commit()
Exemplo n.º 13
0
class Quarantine2Request(EvtHandler):
    """When a quarantine has been added/updated/deleted, we register a
    bofh_quarantine_refresh bofhd_request on the apropriate
    start_date, end_date and disable_until dates.
    """
    def __init__(self):
        self.br = BofhdRequests(db, const)
        self.eq = EntityQuarantine(db)

    def get_triggers(self):
        return ("quarantine_add", "quarantine_mod", "quarantine_del")

    def _get_quarantine(self, entity_id, q_type):
        self.eq.clear()
        try:
            self.eq.find(entity_id)
        except Errors.NotFoundError:
            return None
        qdata = self.eq.get_entity_quarantine(q_type)
        if not qdata:
            return None
        return qdata[0]

    def notify_quarantine_add(self, evt, params):
        # Register a bofh_quarantine_refresh on start, end and
        # disable_date
        qdata = self._get_quarantine(evt['subject_entity'], params['q_type'])
        if not qdata:
            return True
        for when in ('start_date', 'end_date', 'disable_until'):
            if qdata[when] is not None:
                self.br.add_request(None,
                                    qdata[when],
                                    const.bofh_quarantine_refresh,
                                    evt['subject_entity'],
                                    None,
                                    state_data=int(params['q_type']))
            db.commit()
        return True

    def notify_quarantine_mod(self, evt, params):
        # Currently only disable_until is affected by quarantine_mod.
        qdata = self._get_quarantine(evt['subject_entity'], params['q_type'])
        if not qdata:
            return True
        if qdata['disable_until']:
            self.br.add_request(None,
                                qdata['disable_until'],
                                const.bofh_quarantine_refresh,
                                evt['subject_entity'],
                                None,
                                state_data=int(params['q_type']))

        self.br.add_request(None,
                            self.br.now,
                            const.bofh_quarantine_refresh,
                            evt['subject_entity'],
                            None,
                            state_data=int(params['q_type']))
        db.commit()
        return True

    def notify_quarantine_del(self, evt, params):
        # Remove existing requests for this entity_id/quarantine_type
        # combination as they are no longer needed
        for row in self.br.get_requests(entity_id=evt['subject_entity'],
                                        operation=int(
                                            const.bofh_quarantine_refresh)):
            if int(row['state_data']) == int(params['q_type']):
                self.br.delete_request(request_id=row['request_id'])
        self.br.add_request(None,
                            self.br.now,
                            const.bofh_quarantine_refresh,
                            evt['subject_entity'],
                            None,
                            state_data=int(params['q_type']))
        db.commit()
        return True
Exemplo n.º 14
0
def is_valid_request(req_id):
    # The request may have been canceled very recently
    br = BofhdRequests(db, const)
    for r in br.get_requests(request_id=req_id):
        return True
    return False
Exemplo n.º 15
0
class MoveStudentProcessor(object):
    def __init__(self,
                 db,
                 co,
                 ou_perspective,
                 emne_info_file,
                 studconfig_file,
                 studieprogs_file,
                 default_spread=None):
        self.db = db
        self.co = co
        self.br = BofhdRequests(self.db, self.co)
        self.default_spread = default_spread
        logger.debug("Preparing autostud framework")
        self.autostud = AutoStud.AutoStud(self.db,
                                          logger.getChild('autostud'),
                                          debug=False,
                                          cfg_file=studconfig_file,
                                          studieprogs_file=studieprogs_file,
                                          emne_info_file=emne_info_file,
                                          ou_perspective=ou_perspective)

    def process_requests(self, student_info_file):
        rows = self.br.get_requests(operation=self.co.bofh_move_student)
        if not rows:
            return

        # Set self.fnr2move_student
        self.set_fnr2move_student(rows)

        logger.debug("Starting callbacks to find: %s" % self.fnr2move_student)
        self.autostud.start_student_callbacks(student_info_file,
                                              self.move_student_callback)

        self.move_remaining_users()

    def move_remaining_users(self):
        # Move remaining users to pending disk
        disk = Factory.get('Disk')(self.db)
        disk.find_by_path(cereconf.AUTOSTUD_PENDING_DISK)
        logger.debug(str(self.fnr2move_student.values()))
        for tmp_stud in self.fnr2move_student.values():
            for account_id, request_id, requestee_id in tmp_stud:
                logger.debug("Sending %s to pending disk" % repr(account_id))
                self.br.delete_request(request_id=request_id)
                self.br.add_request(requestee_id,
                                    self.br.batch_time,
                                    self.co.bofh_move_user,
                                    account_id,
                                    disk.entity_id,
                                    state_data=int(self.default_spread))
                self.db.commit()

    def set_fnr2move_student(self, rows):
        # Hent ut personens fodselsnummer + account_id
        self.fnr2move_student = {}
        account = Factory.get('Account')(self.db)
        person = Factory.get('Person')(self.db)
        for r in rows:
            if not is_valid_request(self.br, r['request_id']):
                continue
            account.clear()
            account.find(r['entity_id'])
            person.clear()
            person.find(account.owner_id)
            fnr = person.get_external_id(id_type=self.co.externalid_fodselsnr,
                                         source_system=self.co.system_fs)
            if not fnr:
                logger.warn("Not student fnr for: %i" % account.entity_id)
                self.br.delete_request(request_id=r['request_id'])
                self.db.commit()
                continue
            fnr = fnr[0]['external_id']
            self.fnr2move_student.setdefault(fnr, []).append(
                (int(account.entity_id), int(r['request_id']),
                 int(r['requestee_id'])))

    def move_student_callback(self, person_info):
        """We will only move the student if it has a valid fnr from FS,
        and it is not currently on a student disk.

        If the new homedir cannot be determined, user will be moved to a
        pending disk.  process_students moves users from this disk as soon
        as a proper disk can be determined.

        Currently we only operate on the disk whose spread is
        default_spread"""

        fnr = "%06d%05d" % (int(
            person_info['fodselsdato']), int(person_info['personnr']))
        logger.debug("Callback for %s" % fnr)
        try:
            fodselsnr.personnr_ok(fnr)
        except Exception, e:
            logger.exception(e)
            return
        if fnr not in self.fnr2move_student:
            return
        account = Factory.get('Account')(self.db)
        group = Factory.get('Group')(self.db)
        for account_id, request_id, requestee_id in \
                self.fnr2move_student.get(fnr, []):
            account.clear()
            account.find(account_id)
            groups = list(
                int(x["group_id"])
                for x in group.search(member_id=account_id,
                                      indirect_members=False))
            try:
                profile = self.autostud.get_profile(person_info,
                                                    member_groups=groups)
                logger.debug(profile.matcher.debug_dump())
            except AutostudError, msg:
                logger.debug("Error getting profile, using pending: %s" % msg)
                continue

            disks = self.determine_disks(account, request_id, profile, fnr)

            logger.debug(str((fnr, account_id, disks)))
            if disks:
                logger.debug("Destination %s" % repr(disks))
                del (self.fnr2move_student[fnr])
                for disk, spread in disks:
                    self.br.delete_request(request_id=request_id)
                    self.br.add_request(requestee_id,
                                        self.br.batch_time,
                                        self.co.bofh_move_user,
                                        account_id,
                                        disk,
                                        state_data=spread)
                    self.db.commit()
Exemplo n.º 16
0
def process_delete_requests():
    br = BofhdRequests(db, const)
    now = mx.DateTime.now()
    del_file = []
    group = Factory.get('Group')(db)
    account = Factory.get('Account')(db)
    spreads = []
    posix_home = ''
    pwd = '*'
    uid = ''
    gid = ''
    gecos = 'gecos'
    shell = ''
    line = ''

    for r in br.get_requests(operation=const.bofh_delete_user):
        if not is_valid_request(r['request_id']):
            continue
        if not keep_running():
            break
        if r['run_at'] > now:
            continue
        try:
            account.clear()
            account.find(r['entity_id'])
        except Errors.NotFoundError:
            logger.error('Could not find account %s' % r['entity_id'])
            continue
        if account.is_deleted():
            logger.warn("%s is already deleted" % account.account_name)
            br.delete_request(request_id=r['request_id'])
            db.commit()
            continue
        logger.info("Trying to delete account %s", account.account_name)

        blockers = account.get_delete_blockers(ignore_group_memberships=True)
        if blockers:
            logger.error(
                'Manual cleaning required: '
                'Deleting account %s is blocked by: %s', account.account_name,
                ', '.join(blockers))
            continue
        set_operator(r['requestee_id'])
        # Set expire_date (do not export data about this account)
        account.expire_date = br.now
        logger.debug("expire_date for %s registered as %s",
                     account.account_name, br.now)
        account.write_db()
        # check for posix attrs
        posix_user = Factory.get('PosixUser')(db)
        posix_user.clear()
        try:
            posix_user.find(r['entity_id'])
        except Errors.NotFoundError:
            posix_user = None

        # Deal with all the systems that account data is exported to
        spreads = account.get_spread()
        logger.debug("Fetched all spreads for %s, %s", account.account_name,
                     spreads)
        for row in spreads:
            # Account is valid in AD, remove account@ad spread
            if row['spread'] == const.spread_hia_ad_account:
                try:
                    home = account.get_home(row['spread'])
                    account.set_homedir(current_id=home['homedir_id'],
                                        status=const.home_status_archived)
                    account.clear_home(row['spread'])
                except Errors.NotFoundError:
                    logger.debug(
                        "No home in AD for %s, will remove spread to "
                        "AD only.", account.account_name)
                account.delete_spread(row['spread'])
                logger.debug("Deleted account@ad spread for %s",
                             account.account_name)
            # student-accounts usually have account@ldap, remove this
            elif row['spread'] == const.spread_ldap_account:
                account.delete_spread(row['spread'])
                logger.debug("Deleted account@ldap spread for %s",
                             account.account_name)
            # An email account exists, remove account@imap spread,
            # register email account delete
            elif row['spread'] == const.spread_hia_email:
                et = Email.EmailTarget(db)
                try:
                    et.find_by_target_entity(account.entity_id)
                except Errors.NotFoundError:
                    logger.warn(
                        'No email target for %s, removing imap spread '
                        'only.', account.account_name)
                logger.debug("Found e-mail target for %s",
                             account.account_name)
                if et:
                    es = Email.EmailServer(db)
                    es.find(et.email_server_id)
                    del_file.append('EMAIL:' + account.account_name + ':' +
                                    es.name)
                    et.email_target_type = const.email_target_deleted
                    et.write_db()
                account.delete_spread(row['spread'])
            elif row['spread'] in (const.spread_exchange_account,
                                   const.spread_exchange_acc_old):
                et = Email.EmailTarget(db)
                try:
                    et.find_by_target_entity(account.entity_id)
                except Errors.NotFoundError:
                    logger.warn(
                        'No email target for %s, will remove exchange '
                        'spread.', account.account_name)
                if et:
                    et.email_target_type = const.email_target_deleted
                    et.write_db()
                    logger.info("Deleted e-mail target for %s",
                                account.account_name)
                account.delete_spread(row['spread'])
            # Account is valid in nis@hia, remove account@nis spread,
            # register nis-home delete
            elif row['spread'] == const.spread_nis_user:
                if not isinstance(posix_user, Factory.get('PosixUser')):
                    logger.error(
                        "Manual intervention required, no posix "
                        "account is found for account %s",
                        account.account_name)
                    continue
                posix_home = posix_user.get_posix_home(row['spread'])
                uid = posix_user.posix_uid
                gid = posix_user.gid_id
                shell = posix_user.shell
                line = string.join([
                    account.account_name, pwd,
                    str(uid),
                    str(gid), gecos, posix_home,
                    str(shell)
                ], ':')
                line = 'NIS:' + line
                del_file.append(line)
                try:
                    home = account.get_home(row['spread'])
                except Errors.NotFoundError:
                    continue
                account.set_homedir(current_id=home['homedir_id'],
                                    status=const.home_status_archived)
                logger.debug("Set home to archived %s (%s)",
                             home['homedir_id'], row['spread'])
                account.clear_home(row['spread'])
                logger.debug("clear_home in %s", row['spread'])
                account.delete_spread(row['spread'])
            else:
                account.delete_spread(row['spread'])
        if posix_user:
            posix_user.delete_posixuser()

        # Remove account from all groups
        for g in group.search(member_id=account.entity_id,
                              indirect_members=False):
            group.clear()
            group.find(g['group_id'])
            group.remove_member(account.entity_id)
        # All done, remove request, commit results
        account.write_db()
        if posix_user:
            posix_user.write_db()
        br.delete_request(request_id=r['request_id'])
        db.commit()
    return del_file
Exemplo n.º 17
0
    def misc_list_requests(self, operator, search_by, destination):
        br = BofhdRequests(self.db, self.const)
        ret = []

        if destination == '<me>':
            destination = self._get_account(operator.get_entity_id(),
                                            idtype='id')
            destination = destination.account_name
        if search_by == 'requestee':
            account = self._get_account(destination)
            rows = br.get_requests(operator_id=account.entity_id, given=True)
        elif search_by == 'operation':
            try:
                destination = int(
                    self.const.BofhdRequestOp('br_' + destination))
            except Errors.NotFoundError:
                raise CerebrumError("Unknown request operation %s" %
                                    destination)
            rows = br.get_requests(operation=destination)
        elif search_by == 'disk':
            disk_id = self._get_disk(destination)[1]
            rows = br.get_requests(destination_id=disk_id)
        elif search_by == 'account':
            account = self._get_account(destination)
            rows = br.get_requests(entity_id=account.entity_id)
        else:
            raise CerebrumError("Unknown search_by criteria")

        for r in rows:
            op = self.const.BofhdRequestOp(r['operation'])
            dest = None
            ent_name = None
            if op in (self.const.bofh_move_user, self.const.bofh_move_request,
                      self.const.bofh_move_user_now):
                disk = self._get_disk(r['destination_id'])[0]
                dest = disk.path
            elif op in (self.const.bofh_move_give, ):
                dest = self._get_entity_name(r['destination_id'],
                                             self.const.entity_group)
            elif op in (self.const.bofh_email_create,
                        self.const.bofh_email_delete):
                dest = self._get_entity_name(r['destination_id'],
                                             self.const.entity_host)
            elif op in (self.const.bofh_sympa_create,
                        self.const.bofh_sympa_remove):
                ea = Email.EmailAddress(self.db)
                if r['destination_id'] is not None:
                    ea.find(r['destination_id'])
                    dest = ea.get_address()
                ea.clear()
                try:
                    ea.find(r['entity_id'])
                except Errors.NotFoundError:
                    ent_name = "<not found>"
                else:
                    ent_name = ea.get_address()
            if ent_name is None:
                ent_name = self._get_entity_name(r['entity_id'],
                                                 self.const.entity_account)
            if r['requestee_id'] is None:
                requestee = ''
            else:
                requestee = self._get_entity_name(r['requestee_id'],
                                                  self.const.entity_account)
            ret.append({
                'when': r['run_at'],
                'requestee': requestee,
                'op': six.text_type(op),
                'entity': ent_name,
                'destination': dest,
                'args': r['state_data'],
                'id': r['request_id']
            })
        ret.sort(lambda a, b: cmp(a['id'], b['id']))
        return ret
Exemplo n.º 18
0
 def __init__(self):
     self.br = BofhdRequests(db, const)
     self.eq = EntityQuarantine(db)