Exemplo n.º 1
0
    def query_1(self, query, params=()):
        """
        Perform an SQL query that should yield at most one row.

        Like query(), but:

        1. The method can raise the exceptions NotFoundError
           (indicating a query returned no rows) or TooManyRowsError
           (query returned more than one row).

        2. When the query returns a single row, but each returned row
           contains multiple columns, the method will return a single
           row object.

        3. Otherwise (i.e. the query returns a single row with a
           single column) the method will return the value within the
           row object (and not the row object itself).
        """
        res = self.query(query, params)
        if len(res) == 1:
            if len(res[0]) == 1:
                return res[0][0]
            return res[0]
        elif len(res) == 0:
            raise Errors.NotFoundError(repr(params))
        else:
            raise Errors.TooManyRowsError(repr(params))
Exemplo n.º 2
0
    def delete_trait(self, code):
        """Remove the entity's trait identified by code value."""

        code = _EntityTraitCode(code)
        # get_traits populates __traits as a side effect
        if code not in self.get_traits():
            raise Errors.NotFoundError(code)
        if code in self.__trait_updates:
            if self.__trait_updates[code] == 'INSERT':
                del self.__trait_updates[code]
                del self.__traits[code]
                return
            del self.__trait_updates[code]
        params = self._pickle_fixup(self.__traits[code])
        binds = {'entity_id': self.entity_id, 'code': int(code)}
        exists_stmt = """
        SELECT EXISTS (
          SELECT 1
          FROM [:table schema=cerebrum name=entity_trait]
          WHERE entity_id=:entity_id AND code=:code
        )
        """
        if not self.query_1(exists_stmt, binds):
            # False positive
            return
        delete_stmt = """
        DELETE FROM [:table schema=cerebrum name=entity_trait]
        WHERE entity_id=:entity_id AND code=:code
        """
        self.execute(delete_stmt, binds)
        self._db.log_change(self.entity_id,
                            self.clconst.trait_del,
                            None,
                            change_params=params)
        del self.__traits[code]
Exemplo n.º 3
0
 def get_project_id(self):
     """Get the project ID of this project"""
     ret = self.get_external_id(id_type=self.const.externalid_project_id)
     if ret:
         return ret[0]['external_id']
     raise Errors.NotFoundError(
         'Mandatory project ID not found for {entity}'.format(
             entity=self.entity_id))
Exemplo n.º 4
0
 def get_fullname(self):
     """The GECOS contains the full name the user wants to be
     associated with POSIX account. This method's return value will
     also be used to generate an email-address if the posix account
     is not owned by an actual person."""
     if self.owner_type != int(self.const.entity_person):
         if self.gecos is not None:
             return self.gecos
         raise Errors.NotFoundError('Name (GECOS) not set for'
                                    'non-personal PosixUser.')
     return self.__super.get_fullname()
Exemplo n.º 5
0
 def select_extid(entity_id, id_type):
     """ Get preferred fnr for a given person_id. """
     ext_ids = {
         int(r['source_system']): r['external_id']
         for r in person.search_external_ids(entity_id=entity_id,
                                             source_system=sys_lookup_order,
                                             id_type=id_type)
     }
     for pref in sys_lookup_order:
         if ext_ids.get(int(pref)):
             return ext_ids[int(pref)]
     raise Errors.NotFoundError("No fnr for person_id=%r" % (entity_id, ))
Exemplo n.º 6
0
def add_cname_record(db, cname_record_name, target_name, fail_on_exists=True):
    """
    Creates a CNAME-record.

    If fail_on_exists=False, it will simply return without doing anything,
    if the CNAME-record already exists.
    This is due to the method being used by OU._setup_project_hosts, which
    can be run several times for the same project when it is reconfigured.

    :param db: A Cerebrum-database instance
    :type db: Cerebrum.Database
    :param cname_record_name: FQDN of the CNAME-record
    :type cname_record_name: str
    :param target_name: FQDN of the target domain
    :type target_name: str
    :param fail_on_exists: True or False
    :type fail_on_exists: bool
    """

    cname = CNameRecord(db)
    dns_owner = DnsOwner(db)
    constants = Factory.get('Constants')

    try:
        dns_owner.find_by_name(target_name)
        proxy_dns_owner_ref = dns_owner.entity_id
    except Errors.NotFoundError:
        raise Errors.NotFoundError('%s does not exist.' % target_name)

    dns_owner.clear()

    try:
        dns_owner.find_by_name(cname_record_name)
    except Errors.NotFoundError:
        dns_owner.populate(constants.DnsZone(cereconf.DNS_DEFAULT_ZONE),
                           cname_record_name)
        dns_owner.write_db()
    cname_dns_owner_ref = dns_owner.entity_id

    try:
        cname.find_by_cname_owner_id(cname_dns_owner_ref)
        if fail_on_exists:
            raise Errors.RealityError('CNAME %s already exists.'
                                      % cname_record_name)
    except Errors.NotFoundError:
        cname.populate(cname_dns_owner_ref,
                       proxy_dns_owner_ref)
        cname.write_db()
Exemplo n.º 7
0
    def _populate_dnsowner(self, hostname):
        """Create or update a DnsOwner connected to the given project.

        The DnsOwner is given a trait, to affiliate it with this project-OU.

        This should rather be put in the DNS module, but due to its complexity,
        its weird layout, and my lack of IQ points to understand it, I started
        just using its API instead.

        :param str hostname: The given *FQDN* for the host.

        :rtype: DnsOwner object
        :return:
            The DnsOwner object that is created or updated.
        """
        dns_owner = DnsOwner.DnsOwner(self._db)
        dnsfind = Utils.Find(self._db, cereconf.DNS_DEFAULT_ZONE)
        ipv6number = IPv6Number.IPv6Number(self._db)
        aaaarecord = AAAARecord.AAAARecord(self._db)
        ipnumber = IPNumber.IPNumber(self._db)
        arecord = ARecord.ARecord(self._db)

        try:
            dns_owner.find_by_name(hostname)
        except Errors.NotFoundError:
            # TODO: create owner here?
            dns_owner.populate(self.const.DnsZone(cereconf.DNS_DEFAULT_ZONE),
                               hostname)
            dns_owner.write_db()
        # Affiliate with project:
        dns_owner.populate_trait(self.const.trait_project_host,
                                 target_id=self.entity_id)
        dns_owner.write_db()
        for (subnets, ipnum, record, ipstr) in (
                (self.ipv6_subnets, ipv6number, aaaarecord, "IPv6"),
                (self.ipv4_subnets, ipnumber, arecord, "IPv4")):
            # TODO: check if dnsowner already has an ip address.
            try:
                ip = dnsfind.find_free_ip(subnets.next(), no_of_addrs=1)[0]
            except StopIteration:
                raise Errors.NotFoundError("No %s-subnet for project %s" %
                                           (ipstr, self.get_project_id()))
            ipnum.populate(ip)
            ipnum.write_db()
            record.populate(dns_owner.entity_id, ipnum.entity_id)
            record.write_db()
        return dns_owner
Exemplo n.º 8
0
    def delete(self, username):
        """
        Delete a username entry from legacy_users.

        :type username: str
        :param username: The username to remove.
        """
        if not self.exists(username):
            raise Errors.NotFoundError("No legacy username %s" %
                                       repr(username))
        binds = {'username': six.text_type(username)}
        stmt = """
            DELETE FROM [:table schema=cerebrum name=legacy_users]
            WHERE user_name = :username
        """
        logger.debug('Deleting legacy_users user_name=%r', username)
        self.execute(stmt, binds)
Exemplo n.º 9
0
    def delete(self, code):
        """
        Remove a given employment code.

        :type code: int

        :raises: NotFoundError
        """
        if not self.exists(code):
            raise Errors.NotFoundError("No employment code=%r" % (code, ))

        binds = {'stillingskode': int(code)}
        stmt = """
          DELETE FROM [:table schema=cerebrum name=person_stillingskoder]
          WHERE stillingskode = :stillingskode
        """
        logger.debug("removing employment code=%r", code)
        return self.execute(stmt, binds)
Exemplo n.º 10
0
    def get_owner(self, guestname):
        """
        Find owner for the given guest account.

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

        @rtype: int
        @return: entity_id of owner
        """
        ac = Factory.get('Account')(self.db)
        ac.find_by_name(guestname)
        owner = ac.get_trait(self.co.trait_uio_guest_owner)
        if not owner:
            raise Errors.NotFoundError("Not a guest account.")
        if not owner['target_id']:
            raise GuestAccountException("Already available.")
        return int(owner['target_id'])
Exemplo n.º 11
0
    def find_by_tsd_projectname(self, project_name):
        """Finds Project OU by project name.

        This is a L{find}-method, it will populate this entity with any project
        it finds.

        :param str project_name: The short-name of the project to find.

        :raise NotFoundError:
            If the project is not found.
        :raise TooManyRowsError:
            If multiple projects matches the name (should not be possible).
        """
        matched = self.search_tsd_projects(name=project_name, exact_match=True)
        if not matched:
            raise Errors.NotFoundError(u"Unknown project: %s" % project_name)
        if len(matched) != 1:
            raise Errors.TooManyRowsError(
                u"Found several OUs with given name: %s" % project_name)
        return self.find(matched[0]['entity_id'])
Exemplo n.º 12
0
 def delay_request(self, request_id, minutes=10):
     for r in self.get_requests(request_id):
         # Note: the semantics of time objects is DB driver
         # dependent, and not standardised in PEP 249.
         # PgSQL will convert to ticks when forced into int().
         t = int(r['run_at'])
         # don't use self.now, it's a DateTime object.
         now = time.time()
         if t < now:
             t = now
         when = self._db.TimestampFromTicks(int(t + minutes * 60))
         self._db.execute(
             """
             UPDATE [:table schema=cerebrum name=bofhd_request]
             SET run_at=:when WHERE request_id=:id""", {
                 'when': when,
                 'id': request_id
             })
         return
     raise Errors.NotFoundError("No such request %d" % request_id)
Exemplo n.º 13
0
        def get_available_dfg_name(basename):
            group = Factory.get('Group')(self._db)

            def alternatives(base):
                # base -> base, base1, base2, ... base9
                yield base
                if len(base) >= 8:
                    base = base[:-1]
                for i in range(1, 10):
                    yield base + str(i)

            for name in alternatives(basename):
                try:
                    group.find_by_name(name)
                    group.clear()
                    continue
                except Errors.NotFoundError:
                    return name
            # TODO: Better exception?
            raise Errors.NotFoundError(
                "Unable to find a group name for {!s}".format(basename))
Exemplo n.º 14
0
    def get_tsd_project_id(self):
        """Helper method for getting the ou_id for the account's project.

        @rtype: int
        @return:
            The entity_id for the TSD project the account is affiliated with.

        @raise NotFoundError:
            If the account is not affiliated with any project.

        @raise Exception:
            If the account has more than one project affiliation, which is not
            allowed in TSD, or if the account is not affiliated with any
            project.
        """
        rows = self.list_accounts_by_type(
            account_id=self.entity_id,
            affiliation=self.const.affiliation_project)
        assert len(rows) < 2, "Account affiliated with more than one project"
        for row in rows:
            return row['ou_id']
        raise Errors.NotFoundError('Account not affiliated with any project')
Exemplo n.º 15
0
    def _find_legacy_username(self, person, ssn, legacy_type):
        new_ac = Factory.get('Account')(self._db)

        for row in sorted(LegacyUsers(self._db).search(ssn=ssn,
                                                       type=legacy_type),
                          key=lambda r: (r['source'], r['user_name'])):
            legacy_username = row['user_name']
            if not self.is_valid_uit_name(legacy_username):
                logger.debug('skipping invalid legacy_username %r',
                             legacy_username)
                continue

            # valid username found in legacy for this ssn
            # check that its not already used in BAS!
            new_ac.clear()
            try:
                new_ac.find_by_name(legacy_username)
            except Errors.NotFoundError:
                logger.debug('Found free legacy username %r', legacy_username)
                return legacy_username

            # legacy_username tied to fnr already used in BAS. We have an
            # error situation!
            if new_ac.owner_id == person.entity_id:
                raise RuntimeError("Person %s already has account %s in BAS!" %
                                   (ssn, new_ac.account_name))
            else:
                # and used by another person!
                # raise Errors.IntegrityError("Legacy account %s not owned
                # by person %s in BAS!" (legacy_username,fnr))
                logger.warning(
                    "Legacy account %s not owned by person %s in BAS,"
                    " continue with next (if any) legacy username",
                    legacy_username, ssn)
                continue
        raise Errors.NotFoundError("No avaliable legacy username found")
Exemplo n.º 16
0
 def find_by_name(self, component_name):
     self.__super.find_by_name(component_name)
     if self.entity_type != self.const.entity_hostpolicy_atom:
         self.clear()
         raise Errors.NotFoundError('Could not find atom with name: %s' %
                                    component_name)