diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py index a128b3f8d2..d0aa7dcddd 100644 --- a/tempest/cmd/cleanup.py +++ b/tempest/cmd/cleanup.py @@ -54,17 +54,17 @@ associated with the Tempest and alternate Tempest users and projects but will not delete the projects themselves. **--dry-run**: Creates a report (``./dry_run.json``) of the projects that will -be cleaned up (in the ``_tenants_to_clean`` dictionary [1]_) and the global +be cleaned up (in the ``_projects_to_clean`` dictionary [1]_) and the global objects that will be removed (domains, flavors, images, roles, projects, and users). Once the cleanup command is executed (e.g. run without parameters), running it again with **--dry-run** should yield an empty report. **--help**: Print the help text for the command and parameters. -.. [1] The ``_tenants_to_clean`` dictionary in ``dry_run.json`` lists the +.. [1] The ``_projects_to_clean`` dictionary in ``dry_run.json`` lists the projects that ``tempest cleanup`` will loop through to delete child objects, but the command will, by default, not delete the projects - themselves. This may differ from the ``tenants`` list as you can clean + themselves. This may differ from the ``projects`` list as you can clean the Tempest and alternate Tempest users and projects but they will not be deleted unless the **--delete-tempest-conf-objects** flag is used to force their deletion. @@ -111,13 +111,13 @@ class TempestCleanup(command.Command): self.admin_id = "" self.admin_role_id = "" - self.admin_tenant_id = "" + self.admin_project_id = "" self._init_admin_ids() self.admin_role_added = [] # available services - self.tenant_services = cleanup_service.get_tenant_cleanup_services() + self.project_services = cleanup_service.get_project_cleanup_services() self.global_services = cleanup_service.get_global_cleanup_services() if parsed_args.init_saved_state: @@ -133,24 +133,24 @@ class TempestCleanup(command.Command): is_save_state = False if is_dry_run: - self.dry_run_data["_tenants_to_clean"] = {} + self.dry_run_data["_projects_to_clean"] = {} admin_mgr = self.admin_mgr - # Always cleanup tempest and alt tempest tenants unless + # Always cleanup tempest and alt tempest projects unless # they are in saved state json. Therefore is_preserve is False kwargs = {'data': self.dry_run_data, 'is_dry_run': is_dry_run, 'saved_state_json': self.json_data, 'is_preserve': False, 'is_save_state': is_save_state} - tenant_service = cleanup_service.TenantService(admin_mgr, **kwargs) - tenants = tenant_service.list() - print("Process %s tenants" % len(tenants)) + project_service = cleanup_service.ProjectService(admin_mgr, **kwargs) + projects = project_service.list() + print("Process %s projects" % len(projects)) - # Loop through list of tenants and clean them up. - for tenant in tenants: - self._add_admin(tenant['id']) - self._clean_tenant(tenant) + # Loop through list of projects and clean them up. + for project in projects: + self._add_admin(project['id']) + self._clean_project(project) kwargs = {'data': self.dry_run_data, 'is_dry_run': is_dry_run, @@ -169,49 +169,51 @@ class TempestCleanup(command.Command): self._remove_admin_user_roles() def _remove_admin_user_roles(self): - tenant_ids = self.admin_role_added - LOG.debug("Removing admin user roles where needed for tenants: %s", - tenant_ids) - for tenant_id in tenant_ids: - self._remove_admin_role(tenant_id) + project_ids = self.admin_role_added + LOG.debug("Removing admin user roles where needed for projects: %s", + project_ids) + for project_id in project_ids: + self._remove_admin_role(project_id) - def _clean_tenant(self, tenant): - print("Cleaning tenant: %s " % tenant['name']) + def _clean_project(self, project): + print("Cleaning project: %s " % project['name']) is_dry_run = self.options.dry_run dry_run_data = self.dry_run_data is_preserve = not self.options.delete_tempest_conf_objects - tenant_id = tenant['id'] - tenant_name = tenant['name'] - tenant_data = None + project_id = project['id'] + project_name = project['name'] + project_data = None if is_dry_run: - tenant_data = dry_run_data["_tenants_to_clean"][tenant_id] = {} - tenant_data['name'] = tenant_name + project_data = dry_run_data["_projects_to_clean"][project_id] = {} + project_data['name'] = project_name kwargs = {"username": CONF.auth.admin_username, "password": CONF.auth.admin_password, - "tenant_name": tenant['name']} + "project_name": project['name']} mgr = clients.Manager(credentials=credentials.get_credentials( **kwargs)) - kwargs = {'data': tenant_data, + kwargs = {'data': project_data, 'is_dry_run': is_dry_run, 'saved_state_json': None, 'is_preserve': is_preserve, 'is_save_state': False, - 'tenant_id': tenant_id} - for service in self.tenant_services: + 'project_id': project_id} + for service in self.project_services: svc = service(mgr, **kwargs) svc.run() def _init_admin_ids(self): - tn_cl = self.admin_mgr.tenants_client - rl_cl = self.admin_mgr.roles_client + pr_cl = self.admin_mgr.projects_client + rl_cl = self.admin_mgr.roles_v3_client + rla_cl = self.admin_mgr.role_assignments_client + us_cl = self.admin_mgr.users_v3_client - tenant = identity.get_tenant_by_name(tn_cl, - CONF.auth.admin_project_name) - self.admin_tenant_id = tenant['id'] - - user = identity.get_user_by_username(tn_cl, self.admin_tenant_id, - CONF.auth.admin_username) + project = identity.get_project_by_name(pr_cl, + CONF.auth.admin_project_name) + self.admin_project_id = project['id'] + user = identity.get_user_by_project(us_cl, rla_cl, + self.admin_project_id, + CONF.auth.admin_username) self.admin_id = user['id'] roles = rl_cl.list_roles()['roles'] @@ -236,7 +238,7 @@ class TempestCleanup(command.Command): dest='delete_tempest_conf_objects', default=False, help="Force deletion of the tempest and " - "alternate tempest users and tenants.") + "alternate tempest users and projects.") parser.add_argument('--dry-run', action="store_true", dest='dry_run', default=False, help="Generate JSON file:" + DRY_RUN_JSON + @@ -247,44 +249,44 @@ class TempestCleanup(command.Command): def get_description(self): return 'Cleanup after tempest run' - def _add_admin(self, tenant_id): - rl_cl = self.admin_mgr.roles_client + def _add_admin(self, project_id): + rl_cl = self.admin_mgr.roles_v3_client needs_role = True - roles = rl_cl.list_user_roles_on_project(tenant_id, + roles = rl_cl.list_user_roles_on_project(project_id, self.admin_id)['roles'] for role in roles: if role['id'] == self.admin_role_id: needs_role = False - LOG.debug("User already had admin privilege for this tenant") + LOG.debug("User already had admin privilege for this project") if needs_role: - LOG.debug("Adding admin privilege for : %s", tenant_id) - rl_cl.create_user_role_on_project(tenant_id, self.admin_id, + LOG.debug("Adding admin privilege for : %s", project_id) + rl_cl.create_user_role_on_project(project_id, self.admin_id, self.admin_role_id) - self.admin_role_added.append(tenant_id) + self.admin_role_added.append(project_id) - def _remove_admin_role(self, tenant_id): - LOG.debug("Remove admin user role for tenant: %s", tenant_id) + def _remove_admin_role(self, project_id): + LOG.debug("Remove admin user role for projectt: %s", project_id) # Must initialize Admin Manager for each user role # Otherwise authentication exception is thrown, weird id_cl = clients.Manager( credentials.get_configured_admin_credentials()).identity_client - if (self._tenant_exists(tenant_id)): + if (self._project_exists(project_id)): try: - id_cl.delete_role_from_user_on_project(tenant_id, + id_cl.delete_role_from_user_on_project(project_id, self.admin_id, self.admin_role_id) except Exception as ex: - LOG.exception("Failed removing role from tenant which still" + LOG.exception("Failed removing role from project which still" "exists, exception: %s", ex) - def _tenant_exists(self, tenant_id): - tn_cl = self.admin_mgr.tenants_client + def _project_exists(self, project_id): + pr_cl = self.admin_mgr.projects_client try: - t = tn_cl.show_tenant(tenant_id) - LOG.debug("Tenant is: %s", str(t)) + p = pr_cl.show_project(project_id) + LOG.debug("Project is: %s", str(p)) return True except Exception as ex: - LOG.debug("Tenant no longer exists? %s", ex) + LOG.debug("Project no longer exists? %s", ex) return False def _init_state(self): diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py index c75bc859c3..e61f9061f0 100644 --- a/tempest/cmd/cleanup_service.py +++ b/tempest/cmd/cleanup_service.py @@ -32,7 +32,7 @@ CONF_NETWORKS = [] CONF_PRIV_NETWORK_NAME = None CONF_PUB_NETWORK = None CONF_PUB_ROUTER = None -CONF_TENANTS = None +CONF_PROJECTS = None CONF_USERS = None IS_CINDER = None @@ -50,7 +50,7 @@ def init_conf(): global CONF_PRIV_NETWORK_NAME global CONF_PUB_NETWORK global CONF_PUB_ROUTER - global CONF_TENANTS + global CONF_PROJECTS global CONF_USERS global IS_CINDER global IS_GLANCE @@ -69,7 +69,7 @@ def init_conf(): CONF_PRIV_NETWORK_NAME = CONF.compute.fixed_network_name CONF_PUB_NETWORK = CONF.network.public_network_id CONF_PUB_ROUTER = CONF.network.public_router_id - CONF_TENANTS = [CONF.auth.admin_project_name] + CONF_PROJECTS = [CONF.auth.admin_project_name] CONF_USERS = [CONF.auth.admin_username] if IS_NEUTRON: @@ -82,14 +82,14 @@ def _get_network_id(net_name, project_name): am = clients.Manager( credentials.get_configured_admin_credentials()) net_cl = am.networks_client - tn_cl = am.tenants_client + pr_cl = am.projects_client networks = net_cl.list_networks() - tenant = identity.get_tenant_by_name(tn_cl, project_name) - t_id = tenant['id'] + project = identity.get_project_by_name(pr_cl, project_name) + p_id = project['id'] n_id = None for net in networks['networks']: - if (net['tenant_id'] == t_id and net['name'] == net_name): + if (net['project_id'] == p_id and net['name'] == net_name): n_id = net['id'] break return n_id @@ -786,14 +786,14 @@ class ImageService(BaseService): class IdentityService(BaseService): def __init__(self, manager, **kwargs): super(IdentityService, self).__init__(kwargs) - self.client = manager.identity_client + self.client = manager.identity_v3_client class UserService(BaseService): def __init__(self, manager, **kwargs): super(UserService, self).__init__(kwargs) - self.client = manager.users_client + self.client = manager.users_v3_client def list(self): users = self.client.list_users()['users'] @@ -872,43 +872,43 @@ class RoleService(BaseService): self.data['roles'][role['id']] = role['name'] -class TenantService(BaseService): +class ProjectService(BaseService): def __init__(self, manager, **kwargs): - super(TenantService, self).__init__(kwargs) - self.client = manager.tenants_client + super(ProjectService, self).__init__(kwargs) + self.client = manager.projects_client def list(self): - tenants = self.client.list_tenants()['tenants'] + projects = self.client.list_projects()['projects'] if not self.is_save_state: - tenants = [tenant for tenant in tenants if (tenant['id'] - not in self.saved_state_json['tenants'].keys() - and tenant['name'] != CONF.auth.admin_project_name)] + projects = [project for project in projects if (project['id'] + not in self.saved_state_json['projects'].keys() + and project['name'] != CONF.auth.admin_project_name)] if self.is_preserve: - tenants = [tenant for tenant in tenants if tenant['name'] - not in CONF_TENANTS] + projects = [project for project in projects if project['name'] + not in CONF_PROJECTS] - LOG.debug("List count, %s Tenants after reconcile", len(tenants)) - return tenants + LOG.debug("List count, %s Projects after reconcile", len(projects)) + return projects def delete(self): - tenants = self.list() - for tenant in tenants: + projects = self.list() + for project in projects: try: - self.client.delete_tenant(tenant['id']) + self.client.delete_project(project['id']) except Exception: - LOG.exception("Delete Tenant exception.") + LOG.exception("Delete project exception.") def dry_run(self): - tenants = self.list() - self.data['tenants'] = tenants + projects = self.list() + self.data['projects'] = projects def save_state(self): - tenants = self.list() - self.data['tenants'] = {} - for tenant in tenants: - self.data['tenants'][tenant['id']] = tenant['name'] + projects = self.list() + self.data['projects'] = {} + for project in projects: + self.data['projects'][project['id']] = project['name'] class DomainService(BaseService): @@ -948,35 +948,35 @@ class DomainService(BaseService): self.data['domains'][domain['id']] = domain['name'] -def get_tenant_cleanup_services(): - tenant_services = [] +def get_project_cleanup_services(): + project_services = [] # TODO(gmann): Tempest should provide some plugin hook for cleanup # script extension to plugin tests also. if IS_NOVA: - tenant_services.append(ServerService) - tenant_services.append(KeyPairService) - tenant_services.append(SecurityGroupService) - tenant_services.append(ServerGroupService) + project_services.append(ServerService) + project_services.append(KeyPairService) + project_services.append(SecurityGroupService) + project_services.append(ServerGroupService) if not IS_NEUTRON: - tenant_services.append(FloatingIpService) - tenant_services.append(NovaQuotaService) + project_services.append(FloatingIpService) + project_services.append(NovaQuotaService) if IS_HEAT: - tenant_services.append(StackService) + project_services.append(StackService) if IS_NEUTRON: - tenant_services.append(NetworkFloatingIpService) + project_services.append(NetworkFloatingIpService) if utils.is_extension_enabled('metering', 'network'): - tenant_services.append(NetworkMeteringLabelRuleService) - tenant_services.append(NetworkMeteringLabelService) - tenant_services.append(NetworkRouterService) - tenant_services.append(NetworkPortService) - tenant_services.append(NetworkSubnetService) - tenant_services.append(NetworkService) - tenant_services.append(NetworkSecGroupService) + project_services.append(NetworkMeteringLabelRuleService) + project_services.append(NetworkMeteringLabelService) + project_services.append(NetworkRouterService) + project_services.append(NetworkPortService) + project_services.append(NetworkSubnetService) + project_services.append(NetworkService) + project_services.append(NetworkSecGroupService) if IS_CINDER: - tenant_services.append(SnapshotService) - tenant_services.append(VolumeService) - tenant_services.append(VolumeQuotaService) - return tenant_services + project_services.append(SnapshotService) + project_services.append(VolumeService) + project_services.append(VolumeQuotaService) + return project_services def get_global_cleanup_services(): @@ -986,7 +986,7 @@ def get_global_cleanup_services(): if IS_GLANCE: global_services.append(ImageService) global_services.append(UserService) - global_services.append(TenantService) + global_services.append(ProjectService) global_services.append(DomainService) global_services.append(RoleService) return global_services diff --git a/tempest/common/identity.py b/tempest/common/identity.py index 6e496d3973..eaf651b4cd 100644 --- a/tempest/common/identity.py +++ b/tempest/common/identity.py @@ -20,6 +20,15 @@ from tempest.lib import exceptions as lib_exc CONF = config.CONF +def get_project_by_name(client, project_name): + projects = client.list_projects({'name': project_name})['projects'] + for project in projects: + if project['name'] == project_name: + return project + raise lib_exc.NotFound('No such project(%s) in %s' % (project_name, + projects)) + + def get_tenant_by_name(client, tenant_name): tenants = client.list_tenants()['tenants'] for tenant in tenants: @@ -36,6 +45,18 @@ def get_user_by_username(client, tenant_id, username): raise lib_exc.NotFound('No such user(%s) in %s' % (username, users)) +def get_user_by_project(users_client, roles_client, project_id, username): + users = users_client.list_users(**{'name': username})['users'] + users_in_project = roles_client.list_role_assignments( + **{'scope.project.id': project_id})['role_assignments'] + for user in users: + if user['name'] == username: + for u in users_in_project: + if u['user']['id'] == user['id']: + return user + raise lib_exc.NotFound('No such user(%s) in %s' % (username, users)) + + def identity_utils(clients): """A client that abstracts v2 and v3 identity operations.