def test_project_termination(self): """Terminated projects should remove its attributes.""" entity_trait = EntityTrait(self._db) self.setup_project('del_me') eid = self._ou.entity_id self._ou.terminate() self.assertEqual(eid, self._ou.entity_id) # The OU object itself must remain, and its project ID and project name # No accounts: self.assertEqual(0, len(self._ac.list_accounts_by_type( ou_id=eid, filter_expired=False))) # No affiliated persons: self.assertEqual(0, len(self._pe.list_affiliations( ou_id=eid, include_deleted=True))) # Checking for different types of traits. # Are there any traits that should be left? # No groups: # list_traits returns an iterator instead of a list groups = tuple(self._gr.list_traits( code=self._co.trait_project_group, target_id=eid)) self.assertEqual(0, len(groups)) # No hosts: hosts = tuple(entity_trait.list_traits( target_id=eid, code=self._co.trait_project_host)) self.assertEqual(0, len(hosts)) # No subnets: subnets = tuple(entity_trait.list_traits( target_id=eid, code=(self._co.trait_project_subnet6, self._co.trait_project_subnet))) self.assertEqual(0, len(subnets))
def get_student_disks(db): """ Get disks tagged as student disks. """ et = EntityTrait(db) co = Factory.get('Constants')(db) return set( t['entity_id'] for t in et.list_traits(code=co.trait_student_disk))
def populate(self, owner_entity_id): """Create a new VoipAddress in memory. FIXME: check that owner_entity_type is voip_service/person. FIXME: check that owner_entity_id does not own other voipAddresses. """ EntityTrait.populate(self, self.const.entity_voip_address) try: if not self.__in_db: raise RuntimeError("populate() called multiple times.") except AttributeError: self.__in_db = False self.owner_entity_id = owner_entity_id
def populate(self, description, service_type, ou_id): """Create a new VoipService instance in memory. """ EntityTrait.populate(self, self.const.entity_voip_service) try: if not self.__in_db: raise RuntimeError("populate() called multiple times.") except AttributeError: self.__in_db = False self.description = description self.service_type = self.const.VoipServiceTypeCode(int(service_type)) self.ou_id = int(ou_id)
def get_default_host_quota(db, host_id): """ Get default disk quota from host trait. :rtype: int :return: Returns the default disk quota set on the host, or None if no default quota is set. """ et = EntityTrait(db) try: et.find(host_id) trait = et.get_trait(_Co.trait_host_disk_quota) except Errors.NotFoundError: trait = None trait = trait or {} return trait.get('numval')
def has_disk_quota(db, disk_id): """ Check if disk has disk quotas enabled. Quotas are enabled/disabled by setting a disk quota trait on the disk. The trait may have no default disk quota. :rtype: bool :return: True if quota is enabled. """ et = EntityTrait(db) try: et.find(disk_id) except Errors.NotFoundError: trait = None else: trait = et.get_trait(_Co.trait_disk_quota) return trait is not None
def populate(self, voip_address_id, client_type, sip_enabled, mac_address, client_info): """Create a new VoipClient in memory.""" assert sip_enabled in (True, False) mac_address = self._normalize_mac_address(mac_address) EntityTrait.populate(self, self.const.entity_voip_client) try: if not self.__in_db: raise RuntimeError("populate() called multiple times.") except AttributeError: self.__in_db = False self.voip_address_id = int(voip_address_id) self.client_type = int(self.const.VoipClientTypeCode(client_type)) self.sip_enabled = bool(sip_enabled) self.mac_address = mac_address self.client_info = int(self.const.VoipClientInfoCode(client_info)) self._assert_mac_rules()
def affiliate_entity(self, entity): """Affiliate an entity with this project. :type entity: Group, DnsOwner, DnsSubnet, DnsSubnet6 :param entity: An entity to affiliate with this project """ trait_code = self._get_affiliate_trait(entity.entity_type) trait = EntityTrait(self._db) trait.find(entity.entity_id) trait.populate_trait(trait_code, target_id=self.entity_id, date=DateTime.now()) trait.write_db()
def is_affiliated_entity(self, entity): u""" Check if entity is affiliated with project. :param Entity entity: An entity to check :return bool: Returns True if entity is affiliated with project """ try: trait_code = self._get_affiliate_trait(entity.entity_type) except Errors.CerebrumError: return False try: trait = EntityTrait(self._db) trait.find(entity.entity_id) return trait.get_trait(trait_code)['target_id'] == self.entity_id except Errors.NotFoundError: return False except TypeError: return False
def is_affiliated_entity(self, entity): """Check if entity is affiliated with project. :param Entity entity: An entity to check :return bool: Returns True if entity is affiliated with project """ try: trait_code = self._get_affiliate_trait(entity.entity_type) except Errors.CerebrumError: return False try: trait = EntityTrait(self._db) trait.find(entity.entity_id) return trait.get_trait(trait_code)['target_id'] == self.entity_id except Errors.NotFoundError: return False except TypeError: return False
def delete_common(entity_id, db): """Remove information from the database common to whichever entity we are deleting. """ # Remove spreads # Remove traits # Remove all permissions # Remove from all groups # Remove change_log entries const = Factory.get("Constants")() logger.debug("Deleting common parts for entity %s (id=%s)", fetch_name(entity_id, db), entity_id) es = EntitySpread(db) es.find(entity_id) logger.debug( "Deleting spreads: %s", ", ".join(str(const.Spread(x["spread"])) for x in es.get_spread())) for row in es.get_spread(): es.delete_spread(row["spread"]) et = EntityTrait(db) et.find(entity_id) logger.debug("Deleting traits: %s", ", ".join(str(x) for x in et.get_traits())) # copy(), since delete_trait and get_traits work on the same dict. This is # so silly. for trait_code in et.get_traits().copy(): et.delete_trait(trait_code) remove_target_permissions(entity_id, db) remove_permissions_on_target(entity_id, db) # Kill memberships group = Factory.get("Group")(db) for row in group.search(member_id=entity_id, filter_expired=False): group.clear() group.find(row["group_id"]) logger.debug("Removing %s as member of %s (id=%s)", entity_id, group.group_name, group.entity_id) group.remove_member(entity_id) # Kill change_log entries logger.debug("Cleaning change_log of references to %s", entity_id) # Kill change_log entries (this includes requests linked to this entity) for row in db.get_log_events(subject_entity=entity_id): db.remove_log_event(row["change_id"])
def test_project_termination(self): """Terminated projects should remove its attributes.""" entity_trait = EntityTrait(self._db) self.setup_project('del_me') eid = self._ou.entity_id self._ou.terminate() self.assertEqual(eid, self._ou.entity_id) # The OU object itself must remain, and its project ID and project name # No accounts: self.assertEqual( 0, len(self._ac.list_accounts_by_type(ou_id=eid, filter_expired=False))) # No affiliated persons: self.assertEqual( 0, len(self._pe.list_affiliations(ou_id=eid, include_deleted=True))) # Checking for different types of traits. # Are there any traits that should be left? # No groups: # list_traits returns an iterator instead of a list groups = tuple( self._gr.list_traits(code=self._co.trait_project_group, target_id=eid)) self.assertEqual(0, len(groups)) # No hosts: hosts = tuple( entity_trait.list_traits(target_id=eid, code=self._co.trait_project_host)) self.assertEqual(0, len(hosts)) # No subnets: subnets = tuple( entity_trait.list_traits(target_id=eid, code=(self._co.trait_project_subnet6, self._co.trait_project_subnet))) self.assertEqual(0, len(subnets))
def delete_common(entity_id, db): """Remove information from the database common to whichever entity we are deleting. """ # Remove spreads # Remove traits # Remove all permissions # Remove from all groups # Remove change_log entries const = Factory.get("Constants")() logger.debug("Deleting common parts for entity %s (id=%s)", fetch_name(entity_id, db), entity_id) es = EntitySpread(db) es.find(entity_id) logger.debug("Deleting spreads: %s", ", ".join(str(const.Spread(x["spread"])) for x in es.get_spread())) for row in es.get_spread(): es.delete_spread(row["spread"]) et = EntityTrait(db) et.find(entity_id) logger.debug("Deleting traits: %s", ", ".join(str(x) for x in et.get_traits())) # copy(), since delete_trait and get_traits work on the same dict. This is # so silly. for trait_code in et.get_traits().copy(): et.delete_trait(trait_code) remove_target_permissions(entity_id, db) remove_permissions_on_target(entity_id, db) # Kill memberships group = Factory.get("Group")(db) for row in group.search(member_id=entity_id, filter_expired=False): group.clear() group.find(row["group_id"]) logger.debug("Removing %s as member of %s (id=%s)", entity_id, group.group_name, group.entity_id) group.remove_member(entity_id) # Kill change_log entries logger.debug("Cleaning change_log of references to %s", entity_id) # Kill change_log entries (this includes requests linked to this entity) for row in db.get_log_events(subject_entity=entity_id): db.remove_log_event(row["change_id"])
def terminate(self): """Remove all of a project, except its project ID and name (acronym). The project's entities are deleted by this method, so use with care! For the OU object, it does almost the same as L{delete} except from deleting the entity itself. """ self.write_db() ent = EntityTrait(self._db) ac = Factory.get('Account')(self._db) pu = Factory.get('PosixUser')(self._db) # Delete PosixUsers for row in ac.list_accounts_by_type(ou_id=self.entity_id, filter_expired=False): try: pu.clear() pu.find(row['account_id']) pu.delete_posixuser() except Errors.NotFoundError: # not a PosixUser continue # Remove all project's groups gr = Factory.get('Group')(self._db) for row in gr.list_traits(code=self.const.trait_project_group, target_id=self.entity_id): gr.clear() gr.find(row['entity_id']) gr.delete() # Delete all users for row in ac.list_accounts_by_type(ou_id=self.entity_id): ac.clear() ac.find(row['account_id']) ac.delete() # Remove every trace of person affiliations to the project: pe = Factory.get('Person')(self._db) for row in pe.list_affiliations(ou_id=self.entity_id, include_deleted=True): pe.clear() pe.find(row['person_id']) pe.nuke_affiliation(ou_id=row['ou_id'], affiliation=row['affiliation'], source=row['source_system'], status=row['status']) pe.write_db() # Remove all project's DnsOwners (hosts): dnsowner = DnsOwner.DnsOwner(self._db) policy = PolicyComponent(self._db) update_helper = IntegrityHelper.Updater(self._db) for row in ent.list_traits(code=self.const.trait_project_host, target_id=self.entity_id): # TODO: Could we instead update the Subnet classes to use # Factory.get('Entity'), and make use of EntityTrait there to # handle this? owner_id = row['entity_id'] ent.clear() ent.find(owner_id) ent.delete_trait(row['code']) ent.write_db() # Remove the links to policies if hostpolicy is used for prow in policy.search_hostpolicies(dns_owner_id=owner_id): policy.clear() policy.find(prow['policy_id']) policy.remove_from_host(owner_id) # delete the DNS owner update_helper.full_remove_dns_owner(owner_id) # Delete all subnets subnet = Subnet.Subnet(self._db) subnet6 = IPv6Subnet.IPv6Subnet(self._db) for row in ent.list_traits(code=(self.const.trait_project_subnet6, self.const.trait_project_subnet), target_id=self.entity_id): ent.clear() ent.find(row['entity_id']) ent.delete_trait(row['code']) ent.write_db() if row['code'] == self.const.trait_project_subnet: subnet.clear() subnet.find(row['entity_id']) subnet.delete() if row['code'] == self.const.trait_project_subnet6: subnet6.clear() subnet6.find(row['entity_id']) subnet6.delete() # Remove all data from the OU except for: # The project ID and project name for tr in tuple(self.get_traits()): self.delete_trait(tr) for row in self.get_spread(): self.delete_spread(row['spread']) for row in self.get_contact_info(): self.delete_contact_info(row['source_system'], row['contact_type']) for row in self.get_entity_address(): self.delete_entity_address(row['source_system'], row['address_type']) for row in self.search_name_with_language(entity_id=self.entity_id): # The project name must not be removed, to avoid reuse if row['name_variant'] == self.const.ou_name_acronym: continue self.delete_name_with_language(row['name_variant']) self.write_db()
class VirtHomeMiscConstants(Constants): """Miscellaneous VH constants. """ virtaccount_type = Constants.Account("virtaccount", "Non-federated account in VirtHome") fedaccount_type = Constants.Account("fedaccount", "Federated account in VirtHome") system_virthome = Constants.AuthoritativeSystem('VH', "VirtHome") virthome_contact_email = Constants.ContactInfo( "VH-MAIL", "VirtHome accounts' e-mail address") human_first_name = Constants.ContactInfo( "HUMANFIRST", "VA/FA's human owner's first name") human_last_name = Constants.ContactInfo("HUMANLAST", "VA/FA's human owner's last name") human_full_name = Constants.ContactInfo("HUMANFULL", "VA/FA's human owner's full name") virthome_group_url = Constants.ContactInfo( "VH-GROUP-URL", "Group resource url in VirtHome") # # Bofhd requests ##### va_pending_create = ChangeType( 'e_account', 'pending_create', 'waiting for creation confirmation on %(subject)s') va_email_change = ChangeType( 'e_account', 'pending_email', 'waiting for e-mail change confirmation on %(subject)s') va_group_invitation = ChangeType('e_group', 'pending_invitation', 'issued invitation to join group') va_group_owner_swap = ChangeType('e_group', 'pending_owner_change', 'waiting for a group owner change') va_group_moderator_add = ChangeType('e_group', 'pending_moderator_add', 'waiting for a new group moderator') va_password_recover = ChangeType('e_account', 'password_recover', 'a pending password recovery request') va_reset_expire_date = ChangeType( 'e_account', 'reset_expire_date', "push VA/FA's expire date into the future") # # Various spreads ... spread_ldap_group = SpreadCode('group@ldap', Constants.entity_group, 'Group is exported to LDAP') spread_ldap_account = SpreadCode('account@ldap', Constants.entity_account, 'Account is exported to LDAP') # # Various quarantines ... quarantine_autopassword = QuarantineCode("autopassword", "Password is too old") quarantine_nologin = QuarantineCode("nologin", "Login not allowed") quarantine_pending = QuarantineCode("pending", "Account is pending confirmation") quarantine_disabled = QuarantineCode("disabled", "Account is disabled") trait_user_eula = EntityTrait("user_eula", Constants.entity_account, "Account acknowledged user EULA") trait_group_eula = EntityTrait("group_eula", Constants.entity_account, "Account acknowledged group EULA") trait_user_invited = EntityTrait( "user_invited", Constants.entity_account, "Account has been explicitly invited to join a group") trait_group_forward = EntityTrait( "group_forward", Constants.entity_group, "Redirect URL to use when a new member joins a group.") trait_user_retained = EntityTrait( "user_retained", Constants.entity_account, "Account have been retained from LDAP export.") trait_user_notified = EntityTrait( "user_notified", Constants.entity_account, """Account owner have been emailed (about LDAP export) """)
def terminate(self): """Remove all of a project, except its project ID and name (acronym). The project's entities are deleted by this method, so use with care! For the OU object, it does almost the same as L{delete} except from deleting the entity itself. """ self.write_db() ent = EntityTrait(self._db) ac = Factory.get('Account')(self._db) pu = Factory.get('PosixUser')(self._db) # Delete PosixUsers for row in ac.list_accounts_by_type(ou_id=self.entity_id, filter_expired=False): try: pu.clear() pu.find(row['account_id']) pu.delete_posixuser() except Errors.NotFoundError: # not a PosixUser continue # Remove all project's groups gr = Factory.get('Group')(self._db) for row in gr.list_traits(code=self.const.trait_project_group, target_id=self.entity_id): gr.clear() gr.find(row['entity_id']) gr.delete() # Delete all users for row in ac.list_accounts_by_type(ou_id=self.entity_id): ac.clear() ac.find(row['account_id']) ac.delete() # Remove every trace of person affiliations to the project: pe = Factory.get('Person')(self._db) for row in pe.list_affiliations(ou_id=self.entity_id, include_deleted=True): pe.clear() pe.find(row['person_id']) pe.nuke_affiliation(ou_id=row['ou_id'], affiliation=row['affiliation'], source=row['source_system'], status=row['status']) pe.write_db() # Remove all project's DnsOwners (hosts): dnsowner = dns.DnsOwner.DnsOwner(self._db) policy = PolicyComponent(self._db) update_helper = dns.IntegrityHelper.Updater(self._db) for row in ent.list_traits(code=self.const.trait_project_host, target_id=self.entity_id): # TODO: Could we instead update the Subnet classes to use # Factory.get('Entity'), and make use of EntityTrait there to # handle this? owner_id = row['entity_id'] ent.clear() ent.find(owner_id) ent.delete_trait(row['code']) ent.write_db() # Remove the links to policies if hostpolicy is used for prow in policy.search_hostpolicies(dns_owner_id=owner_id): policy.clear() policy.find(prow['policy_id']) policy.remove_from_host(owner_id) # delete the DNS owner update_helper.full_remove_dns_owner(owner_id) # Delete all subnets subnet = dns.Subnet.Subnet(self._db) subnet6 = dns.IPv6Subnet.IPv6Subnet(self._db) for row in ent.list_traits(code=(self.const.trait_project_subnet6, self.const.trait_project_subnet), target_id=self.entity_id): ent.clear() ent.find(row['entity_id']) ent.delete_trait(row['code']) ent.write_db() if row['code'] == self.const.trait_project_subnet: subnet.clear() subnet.find(row['entity_id']) subnet.delete() if row['code'] == self.const.trait_project_subnet6: subnet6.clear() subnet6.find(row['entity_id']) subnet6.delete() # Remove all data from the OU except for: # The project ID and project name for tr in tuple(self.get_traits()): self.delete_trait(tr) for row in self.get_spread(): self.delete_spread(row['spread']) for row in self.get_contact_info(): self.delete_contact_info(row['source_system'], row['contact_type']) for row in self.get_entity_address(): self.delete_entity_address(row['source_system'], row['address_type']) for row in self.search_name_with_language(entity_id=self.entity_id): # The project name must not be removed, to avoid reuse if row['name_variant'] == self.const.ou_name_acronym: continue self.delete_name_with_language(row['name_variant']) self.write_db()