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))
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]
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))
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()
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, ))
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()
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
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)
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)
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'])
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'])
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)
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))
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')
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")
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)