Beispiel #1
0
 def __init__(self, db):
     self.db = db
     self.const = Factory.get('Constants')(db)
     self.account = Factory.get('Account')(db)
     self.posix_user = Factory.get('PosixUser')(db)
     self.disk_quota = DiskQuota(db)
     self.disk_mapping = OUDiskMapping(db)
def list_disk_quotas(f, disk_id, spread):
    account = Factory.get("Account")(db)
    disk = Factory.get("Disk")(db)
    disk.find(disk_id)

    if not disk.has_quota():
        logger.debug("Skipping %s, no quotas on disk" % disk.path)
        return

    default_quota = disk.get_default_quota()
    logger.debug("Listing quotas on %s" % disk.path)

    if default_quota is None:
        default_quota = ''  # Unlimited
        all_users = False
    else:
        all_users = True

    now = mx.DateTime.now()
    dq = DiskQuota(db)
    for row in dq.list_quotas(spread=spread,
                              disk_id=disk.entity_id,
                              all_users=all_users):
        quota = row['quota']
        if row['override_expiration'] and row['override_expiration'] > now:
            quota = row['override_quota']
        if quota is None:
            quota = default_quota
        home = account.resolve_homedir(account_name=row['entity_name'],
                                       home=row['home'],
                                       disk_path=row['path'])
        f.write("%s:%s:%s\n" % (row['entity_name'], home, quota))
Beispiel #3
0
 def clear_home(self, spread):
     """Remove disk quota before clearing home."""
     try:
         homeinfo = self.get_home(spread)
     except Errors.NotFoundError:
         pass
     else:
         dq = DiskQuota(self._db)
         dq.clear(homeinfo['homedir_id'])
     return self.__super.clear_home(spread)
 def determine_disks(self, account, request_id, profile, fnr):
     disks = []
     spreads = [int(s) for s in profile.get_spreads()]
     try:
         for d_spread in profile.get_disk_spreads():
             if d_spread != self.default_spread:
                 # TBD:  How can all spreads be taken into account?
                 continue
             if d_spread in spreads:
                 try:
                     ah = account.get_home(d_spread)
                     homedir_id = ah['homedir_id']
                     current_disk_id = ah['disk_id']
                 except Errors.NotFoundError:
                     homedir_id, current_disk_id = None, None
                 if self.autostud.disk_tool.get_diskdef_by_diskid(
                         int(current_disk_id)):
                     logger.debug("Already on a student disk")
                     self.br.delete_request(request_id=request_id)
                     self.db.commit()
                     # actually, we remove a bit too much data from
                     # the below dict, but remaining data will be
                     # rebuilt on next run.
                     del (self.fnr2move_student[fnr])
                     raise NextAccount
                 try:
                     new_disk = profile.get_disk(d_spread,
                                                 current_disk_id,
                                                 do_check_move_ok=False)
                     if new_disk == current_disk_id:
                         continue
                     disks.append((new_disk, d_spread))
                     if (self.autostud.disk_tool.using_disk_kvote
                             and homedir_id is not None):
                         from Cerebrum.modules.disk_quota import DiskQuota
                         disk_quota_obj = DiskQuota(self.db)
                         try:
                             cur_quota = disk_quota_obj.get_quota(
                                 homedir_id)
                         except Errors.NotFoundError:
                             cur_quota = None
                         quota = profile.get_disk_kvote(new_disk)
                         if (cur_quota is None
                                 or cur_quota['quota'] != int(quota)):
                             disk_quota_obj.set_quota(homedir_id,
                                                      quota=int(quota))
                 except AutostudError, msg:
                     # Will end up on pending (since we only use one
                     # spread)
                     logger.debug("Error getting disk: %s" % msg)
                     break
     except NextAccount:
         pass  # Stupid python don't have labeled breaks
     return disks
Beispiel #5
0
    def set_homedir(self, *args, **kw):
        """Remove quota information when the user is moved to a disk
        without quotas or where the default quota is larger than his
        existing explicit quota."""

        ret = self.__super.set_homedir(*args, **kw)
        if kw.get('current_id') and kw.get('disk_id'):
            disk = Factory.get("Disk")(self._db)
            disk.find(kw['disk_id'])
            has_quota = disk.has_quota()
            def_quota = disk.get_default_quota()
            dq = DiskQuota(self._db)
            try:
                info = dq.get_quota(kw['current_id'])
            except Errors.NotFoundError:
                pass
            else:
                if not has_quota:
                    # No quota on new disk, so remove the quota information.
                    dq.clear(kw['current_id'])
                elif def_quota is None:
                    # No default quota, so keep the quota information.
                    pass
                else:
                    if (info['override_expiration']
                            and DateTime.now() < info['override_expiration']):
                        old_quota = info['override_quota']
                    else:
                        old_quota = info['quota']
                    if old_quota <= def_quota:
                        dq.clear(kw['current_id'])
        return ret
db = Factory.get('Database')()
db.cl_init(change_program='process_students')
const = Factory.get('Constants')(db)
derived_person_affiliations = {}
person_student_affiliations = {}
processed_students = {}
processed_accounts = {}
keep_account_home = {}
account_id2fnr = {}
posix_tables = False

posix_user_obj = Factory.get('PosixUser')(db)
account_obj = Factory.get('Account')(db)
person_obj = Factory.get('Person')(db)
group_obj = Factory.get('Group')(db)
disk_quota_obj = DiskQuota(db)

debug = 0
max_errors = 50  # Max number of errors to accept in person-callback
posix_spreads = [int(const.Spread(_s)) for _s in cereconf.POSIX_SPREAD_CODES]

# global Command-line alterable variables.  Defined here to make
# pychecker happy
skip_lpr = True  # Must explicitly tell that we want lpr
create_users = move_users = dryrun = update_accounts = False
with_quarantines = False
remove_groupmembers = False
ou_perspective = None
workdir = None
student_info_file = None
studconfig_file = None
Beispiel #7
0
 def _clear_homedir(self, homedir_id):
     # Since disk_quota has a FK to homedir, we need this override
     dq = DiskQuota(self._db)
     dq.clear(homedir_id)
     return self.__super._clear_homedir(homedir_id)
Beispiel #8
0
class AccountPolicy(object):
    def __init__(self, db):
        self.db = db
        self.const = Factory.get('Constants')(db)
        self.account = Factory.get('Account')(db)
        self.posix_user = Factory.get('PosixUser')(db)
        self.disk_quota = DiskQuota(db)
        self.disk_mapping = OUDiskMapping(db)

    def create_basic_account(self, creator_id, owner, uname, np_type=None):
        self.account.clear()
        if not self.account.is_valid_new_uname:
            raise InvalidAccountCreationArgument('Username already taken: %r'
                                                 % uname)
        self.account.populate(uname,
                              owner.entity_type,
                              owner.entity_id,
                              np_type,
                              creator_id,
                              None)
        self.account.write_db()
        new_account = Factory.get('Account')(self.db)
        new_account.find(self.account.entity_id)
        return new_account

    def create_group_account(self, creator_id, uname, owner_group,
                             contact_address, account_type):
        account = self.create_basic_account(creator_id,
                                            owner_group,
                                            uname,
                                            account_type)
        if not is_email(contact_address):
            raise InvalidAccountCreationArgument('Invalid email address: %s',
                                                 contact_address)

        # Unpersonal accounts shouldn't normally have a mail inbox, but they
        # get a forward target for the account, to be sent to those responsible
        # for the account, preferrably a sysadm mail list.
        if hasattr(account, 'add_contact_info'):
            account.add_contact_info(self.const.system_manual,
                                     self.const.contact_email,
                                     contact_address)

        if cereconf.BOFHD_CREATE_UNPERSONAL_QUARANTINE:
            qconst = self.const.Quarantine(
                cereconf.BOFHD_CREATE_UNPERSONAL_QUARANTINE
            )
            account.add_entity_quarantine(qconst, creator_id,
                                          "Not granted for global password "
                                          "auth (ask IT-sikkerhet)",
                                          datetime.date.today().isoformat())
        return account

    def _make_posix_user(self, gid, gecos, shell, expire_date):
        self.posix_user.clear()
        uid = self.posix_user.get_free_uid()
        self.posix_user.populate(
            uid,
            gid,
            gecos,
            shell,
            parent=self.account,
            expire_date=expire_date
        )
        self.posix_user.write_db()

    def _set_user_disk(self, account, disk_id, home_spread, home=None,
                       disk_quota=None):
        if home:
            homedir_id = account.set_homedir(
                disk_id=disk_id,
                status=self.const.home_status_not_created,
                home=home
            )
        else:
            homedir_id = account.set_homedir(
                disk_id=disk_id,
                status=self.const.home_status_not_created
            )
        account.set_home(home_spread, homedir_id)
        if disk_quota:
            self.disk_quota.set_quota(homedir_id, quota=int(disk_quota))

    def _get_ou_disk(self, person):
        # Get highest precedent affiliation
        _, ou_id, aff, _, status, _, _, _, _ = person.list_affiliations(
            person.entity_id)[0]
        # Find the right disk id for this person
        if aff:
            aff = self.const.PersonAffiliation(aff)
        if status:
            status = self.const.PersonAffStatus(status)
        disk_id = utils.get_disk(
            self.db,
            self.disk_mapping,
            ou_id,
            aff,
            status,
            self.const.OUPerspective(cereconf.DEFAULT_OU_PERSPECTIVE))
        home_spread = int(self.const.Spread(cereconf.DEFAULT_HOME_SPREAD))
        return disk_id, home_spread

    def update_account(self, person, account_id, *args, **kwargs):
        self.account.clear()
        self.account.find(account_id)
        return self._update_account(person, *args, **kwargs)

    def _update_account(self, person, affiliations, disks,
                        expire_date, traits=(), spreads=(),
                        make_posix_user=True, gid=None, shell=None,
                        ou_disk=False):
        """Update an account

        Adds traits, spreads and disks to an account, and also promotes posix.
        Note self.account must already populated.
        """
        for trait in traits:
            self.account.populate_trait(code=trait, date=datetime.date.today())
        self.account.write_db()
        if make_posix_user:
            self._make_posix_user(gid, None, shell, expire_date)
        user = self._get_user_obj(make_posix_user)
        for spread in spreads:
            user.add_spread(spread)
        if ou_disk and not disks:
            disk_id, home_spread = self._get_ou_disk(person)
            disks = ({'disk_id': disk_id, 'home_spread': home_spread},)
        for disk in disks:
            self._set_user_disk(user,
                                disk['disk_id'],
                                disk['home_spread'],
                                home=disk.get('home', None),
                                disk_quota=disk.get('disk_quota', None))
        _set_account_types(user, person, affiliations)
        user.write_db()
        return user

    def _get_user_obj(self, posix):
        if posix:
            return self.posix_user
        else:
            return self.account

    def create_personal_account(self, person, affiliations, disks, expire_date,
                                creator_id, uname=None, traits=(), spreads=(),
                                make_posix_user=True, gid=None, shell=None,
                                ou_disk=False):
        """Create a personal account for the given person

        :type person: populated Cerebrum.Utils._dynamic_Person
        :type affiliations: dicts containing keys 'affiliation' and 'ou_id'
        :param affiliations: affiliations to set on the account
        :type disks: Iterable
        :param disks: disks to give the user. Each disk is a dict with
            the required keys 'disk_id', 'home_spread' and optional keys
            'home', 'disk_quota'.
        :param uname: the desired user name
        :param traits: traits to add to the newly created account
        :param spreads: spreads to add to the newly created account
        :param make_posix_user: should the account be a posix user?
        :type ou_disk: bool
        :param ou_disk: should a disk be selected using the OUDiskMapping
            module if disks parameter is empty?
        :return: Account or PosixUser
        """
        user = self._get_user_obj(make_posix_user)
        if uname is None:
            try:
                user_names = user.suggest_unames(person)
            except NotFoundError:
                raise InvalidAccountCreationArgument(
                    'Person %s missing first- or lastname',
                    person.entity_id
                )
            try:
                uname = user_names[0]
            except IndexError:
                raise InvalidAccountCreationArgument(
                    'Could not generate user name for person %s',
                    person.entity_id
                )

        self.account.clear()
        self.account.populate(uname,
                              self.const.entity_person,
                              person.entity_id,
                              None,
                              creator_id,
                              expire_date)
        self.account.write_db()
        user = self._update_account(person, affiliations,
                                    disks, expire_date,
                                    traits=traits, spreads=spreads,
                                    make_posix_user=make_posix_user,
                                    gid=gid,
                                    shell=shell, ou_disk=ou_disk)
        # Returning a new account object to avoid accidentally modifying the
        # current one when creating another account.
        if make_posix_user:
            new_account = Factory.get('PosixUser')(self.db)
        else:
            new_account = Factory.get('Account')(self.db)
        new_account.find(user.entity_id)
        return new_account