blob: f334c36bbf926b87068c8dff2e58e8f3669bd113 [file] [log] [blame]
Matthew Treinishb86cda92013-07-29 11:22:23 -04001# Copyright 2013 IBM Corp.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
zhongjun5b68f502017-07-04 15:28:05 +080015import ipaddress
16
Miguel Lavalleb8fabc52013-08-23 11:19:57 -050017import netaddr
Doug Hellmann583ce2c2015-03-11 14:55:46 +000018from oslo_log import log as logging
Andrea Frittolic3280152015-02-26 12:42:34 +000019import six
Miguel Lavalleb8fabc52013-08-23 11:19:57 -050020
Matthew Treinish3787e4c2016-10-07 21:25:33 -040021from tempest.lib.common import cred_client
Matthew Treinish00ab6be2016-10-07 16:29:18 -040022from tempest.lib.common import cred_provider
Matthew Treinish0650aed2016-10-07 16:36:46 -040023from tempest.lib.common.utils import data_utils
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050024from tempest.lib import exceptions as lib_exc
Andrea Frittolidcd91002017-07-18 11:34:13 +010025from tempest.lib.services import clients
Matthew Treinishb86cda92013-07-29 11:22:23 -040026
27LOG = logging.getLogger(__name__)
28
29
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -070030class DynamicCredentialProvider(cred_provider.CredentialProvider):
Masayuki Igawaa1c3af32017-09-07 10:22:37 +090031 """Creates credentials dynamically for tests
32
33 A credential provider that, based on an initial set of
34 admin credentials, creates new credentials on the fly for
35 tests to use and then discard.
36
37 :param str identity_version: identity API version to use `v2` or `v3`
38 :param str admin_role: name of the admin role added to admin users
39 :param str name: names of dynamic resources include this parameter
40 when specified
41 :param str credentials_domain: name of the domain where the users
42 are created. If not defined, the project
43 domain from admin_credentials is used
44 :param dict network_resources: network resources to be created for
45 the created credentials
46 :param Credentials admin_creds: initial admin credentials
47 :param bool identity_admin_domain_scope: Set to true if admin should be
48 scoped to the domain. By
49 default this is False and the
50 admin role is scoped to the
51 project.
52 :param str identity_admin_role: The role name to use for admin
53 :param list extra_roles: A list of strings for extra roles that should
54 be assigned to all created users
55 :param bool neutron_available: Whether we are running in an environemnt
56 with neutron
57 :param bool create_networks: Whether dynamic project networks should be
58 created or not
59 :param project_network_cidr: The CIDR to use for created project
60 networks
61 :param project_network_mask_bits: The network mask bits to use for
62 created project networks
63 :param public_network_id: The id for the public network to use
64 :param identity_admin_endpoint_type: The endpoint type for identity
65 admin clients. Defaults to public.
66 :param identity_uri: Identity URI of the target cloud
67 """
Matthew Treinishb86cda92013-07-29 11:22:23 -040068
Andrea Frittoli (andreaf)1eb04962015-10-09 14:48:06 +010069 def __init__(self, identity_version, name=None, network_resources=None,
Matthew Treinish75abbcf2016-10-07 16:19:12 -040070 credentials_domain=None, admin_role=None, admin_creds=None,
71 identity_admin_domain_scope=False,
72 identity_admin_role='admin', extra_roles=None,
73 neutron_available=False, create_networks=True,
74 project_network_cidr=None, project_network_mask_bits=None,
Andrea Frittolidcd91002017-07-18 11:34:13 +010075 public_network_id=None, resource_prefix=None,
76 identity_admin_endpoint_type='public', identity_uri=None):
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -070077 super(DynamicCredentialProvider, self).__init__(
Andrea Frittolidcd91002017-07-18 11:34:13 +010078 identity_version=identity_version, identity_uri=identity_uri,
79 admin_role=admin_role, name=name,
80 credentials_domain=credentials_domain,
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +010081 network_resources=network_resources)
82 self.network_resources = network_resources
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -070083 self._creds = {}
Miguel Lavalleb8fabc52013-08-23 11:19:57 -050084 self.ports = []
Matthew Treinish0650aed2016-10-07 16:36:46 -040085 self.resource_prefix = resource_prefix or ''
Matthew Treinish75abbcf2016-10-07 16:19:12 -040086 self.neutron_available = neutron_available
87 self.create_networks = create_networks
88 self.project_network_cidr = project_network_cidr
89 self.project_network_mask_bits = project_network_mask_bits
90 self.public_network_id = public_network_id
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +010091 self.default_admin_creds = admin_creds
Matthew Treinish75abbcf2016-10-07 16:19:12 -040092 self.identity_admin_domain_scope = identity_admin_domain_scope
93 self.identity_admin_role = identity_admin_role or 'admin'
Andrea Frittolidcd91002017-07-18 11:34:13 +010094 self.identity_admin_endpoint_type = identity_admin_endpoint_type
Matthew Treinish75abbcf2016-10-07 16:19:12 -040095 self.extra_roles = extra_roles or []
Yaroslav Lobankov47a93ab2016-02-07 16:32:49 -060096 (self.identity_admin_client,
97 self.tenants_admin_client,
Daniel Mellado82c83a52015-12-09 15:16:49 +000098 self.users_admin_client,
Daniel Mellado7aea5342016-02-09 09:10:12 +000099 self.roles_admin_client,
Daniel Mellado91a26b62016-02-11 11:13:04 +0000100 self.domains_admin_client,
John Warren3961acd2015-10-02 14:38:53 -0400101 self.networks_admin_client,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000102 self.routers_admin_client,
John Warren49c0fe52015-10-22 12:35:54 -0400103 self.subnets_admin_client,
John Warrenf9606e92015-12-10 12:12:42 -0500104 self.ports_admin_client,
Andrea Frittolidcd91002017-07-18 11:34:13 +0100105 self.security_groups_admin_client) = self._get_admin_clients(
106 identity_admin_endpoint_type)
John Warren3961acd2015-10-02 14:38:53 -0400107 # Domain where isolated credentials are provisioned (v3 only).
Andrea Frittolic3280152015-02-26 12:42:34 +0000108 # Use that of the admin account is None is configured.
109 self.creds_domain_name = None
110 if self.identity_version == 'v3':
111 self.creds_domain_name = (
David Kranz87fc7e92015-07-28 14:05:20 -0400112 self.default_admin_creds.project_domain_name or
Andrea Frittoli (andreaf)1eb04962015-10-09 14:48:06 +0100113 self.credentials_domain)
Jamie Lennox15350172015-08-17 10:54:25 +1000114 self.creds_client = cred_client.get_creds_client(
Daniel Melladob04da902015-11-20 17:43:12 +0100115 self.identity_admin_client,
116 self.tenants_admin_client,
Daniel Mellado82c83a52015-12-09 15:16:49 +0000117 self.users_admin_client,
Daniel Mellado7aea5342016-02-09 09:10:12 +0000118 self.roles_admin_client,
Daniel Mellado91a26b62016-02-11 11:13:04 +0000119 self.domains_admin_client,
Daniel Melladob04da902015-11-20 17:43:12 +0100120 self.creds_domain_name)
Matthew Treinishb86cda92013-07-29 11:22:23 -0400121
Andrea Frittolidcd91002017-07-18 11:34:13 +0100122 def _get_admin_clients(self, endpoint_type):
Ken'ichi Ohmichicb67d2d2015-11-19 08:23:22 +0000123 """Returns a tuple with instances of the following admin clients
124
125 (in this order):
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500126 identity
127 network
Matthew Treinishb86cda92013-07-29 11:22:23 -0400128 """
Andrea Frittolidcd91002017-07-18 11:34:13 +0100129 os = clients.ServiceClients(self.default_admin_creds,
130 self.identity_uri)
131 params = {'endpoint_type': endpoint_type}
Andrea Frittolic3280152015-02-26 12:42:34 +0000132 if self.identity_version == 'v2':
Andrea Frittolidcd91002017-07-18 11:34:13 +0100133 return (os.identity_v2.IdentityClient(**params),
134 os.identity_v2.TenantsClient(**params),
135 os.identity_v2.UsersClient(**params),
136 os.identity_v2.RolesClient(**params), None,
137 os.network.NetworksClient(),
138 os.network.RoutersClient(),
139 os.network.SubnetsClient(),
140 os.network.PortsClient(),
141 os.network.SecurityGroupsClient())
Andrea Frittolic3280152015-02-26 12:42:34 +0000142 else:
Andrea Frittoli (andreaf)100d18d2016-05-05 23:34:52 +0100143 # We use a dedicated client manager for identity client in case we
144 # need a different token scope for them.
Colleen Murphycd0bbbd2019-10-01 16:18:36 -0700145 if self.default_admin_creds.system:
146 scope = 'system'
Martin Kopeca28849f2021-01-21 14:06:21 +0000147 elif (self.identity_admin_domain_scope and
148 (self.default_admin_creds.domain_id or
149 self.default_admin_creds.domain_name)):
Colleen Murphycd0bbbd2019-10-01 16:18:36 -0700150 scope = 'domain'
151 else:
152 scope = 'project'
Andrea Frittolidcd91002017-07-18 11:34:13 +0100153 identity_os = clients.ServiceClients(self.default_admin_creds,
154 self.identity_uri,
155 scope=scope)
156 return (identity_os.identity_v3.IdentityClient(**params),
157 identity_os.identity_v3.ProjectsClient(**params),
158 identity_os.identity_v3.UsersClient(**params),
159 identity_os.identity_v3.RolesClient(**params),
160 identity_os.identity_v3.DomainsClient(**params),
161 os.network.NetworksClient(),
162 os.network.RoutersClient(),
163 os.network.SubnetsClient(),
164 os.network.PortsClient(),
165 os.network.SecurityGroupsClient())
Matthew Treinishb86cda92013-07-29 11:22:23 -0400166
Colleen Murphy06374e22019-10-02 14:28:22 -0700167 def _create_creds(self, admin=False, roles=None, scope='project'):
Genadi Chereshnya88ea9ab2016-05-15 14:47:07 +0300168 """Create credentials with random name.
Sean Dague6969b902014-01-28 06:48:37 -0500169
Colleen Murphy06374e22019-10-02 14:28:22 -0700170 Creates user and role assignments on a project, domain, or system. When
171 the admin flag is True, creates user with the admin role on the
172 resource. If roles are provided, assigns those roles on the resource.
173 Otherwise, assigns the user the 'member' role on the resource.
Sean Dague6969b902014-01-28 06:48:37 -0500174
Genadi Chereshnya88ea9ab2016-05-15 14:47:07 +0300175 :param admin: Flag if to assign to the user admin role
176 :type admin: bool
177 :param roles: Roles to assign for the user
178 :type roles: list
Colleen Murphy06374e22019-10-02 14:28:22 -0700179 :param str scope: The scope for the role assignment, may be one of
180 'project', 'domain', or 'system'.
Genadi Chereshnya88ea9ab2016-05-15 14:47:07 +0300181 :return: Readonly Credentials with network resources
Colleen Murphy06374e22019-10-02 14:28:22 -0700182 :raises: Exception if scope is invalid
Sean Dague6969b902014-01-28 06:48:37 -0500183 """
Colleen Murphy06374e22019-10-02 14:28:22 -0700184 if not roles:
185 roles = []
Genadi Chereshnya88ea9ab2016-05-15 14:47:07 +0300186 root = self.name
Sean Dague6969b902014-01-28 06:48:37 -0500187
Colleen Murphy06374e22019-10-02 14:28:22 -0700188 cred_params = {
189 'project': None,
190 'domain': None,
191 'system': None
192 }
193 if scope == 'project':
194 project_name = data_utils.rand_name(
195 root, prefix=self.resource_prefix)
196 project_desc = project_name + '-desc'
197 project = self.creds_client.create_project(
198 name=project_name, description=project_desc)
Sean Dague6969b902014-01-28 06:48:37 -0500199
Colleen Murphy06374e22019-10-02 14:28:22 -0700200 # NOTE(andreaf) User and project can be distinguished from the
201 # context, having the same ID in both makes it easier to match them
202 # and debug.
203 username = project_name + '-project'
204 cred_params['project'] = project
205 elif scope == 'domain':
206 domain_name = data_utils.rand_name(
207 root, prefix=self.resource_prefix)
208 domain_desc = domain_name + '-desc'
209 domain = self.creds_client.create_domain(
210 name=domain_name, description=domain_desc)
211 username = domain_name + '-domain'
212 cred_params['domain'] = domain
213 elif scope == 'system':
214 prefix = data_utils.rand_name(root, prefix=self.resource_prefix)
215 username = prefix + '-system'
216 cred_params['system'] = 'all'
217 else:
218 raise lib_exc.InvalidScopeType(scope=scope)
Matthew Treinishb86cda92013-07-29 11:22:23 -0400219 if admin:
Colleen Murphy06374e22019-10-02 14:28:22 -0700220 username += '-admin'
221 elif roles and len(roles) == 1:
222 username += '-' + roles[0]
223 user_password = data_utils.rand_password()
224 cred_params['password'] = user_password
225 user = self.creds_client.create_user(
226 username, user_password)
227 cred_params['user'] = user
228 roles_to_assign = [r for r in roles]
229 if admin:
230 roles_to_assign.append(self.admin_role)
Lance Bragstadef13f402021-03-04 17:12:10 +0000231 if scope == 'project':
232 self.creds_client.assign_user_role(
233 user, project, self.identity_admin_role)
Andrea Frittoli (andreaf)100d18d2016-05-05 23:34:52 +0100234 if (self.identity_version == 'v3' and
Matthew Treinish75abbcf2016-10-07 16:19:12 -0400235 self.identity_admin_domain_scope):
Andrea Frittoli (andreaf)4bee2e72015-09-22 13:06:18 +0100236 self.creds_client.assign_user_role_on_domain(
Matthew Treinish75abbcf2016-10-07 16:19:12 -0400237 user, self.identity_admin_role)
Matthew Treinish976e8df2014-12-19 14:21:54 -0500238 # Add roles specified in config file
Colleen Murphy06374e22019-10-02 14:28:22 -0700239 roles_to_assign.extend(self.extra_roles)
240 # If there are still no roles, default to 'member'
Matthew Treinish32f98a42015-07-14 19:58:46 -0400241 # NOTE(mtreinish) For a user to have access to a project with v3 auth
242 # it must beassigned a role on the project. So we need to ensure that
243 # our newly created user has a role on the newly created project.
Colleen Murphy06374e22019-10-02 14:28:22 -0700244 if not roles_to_assign and self.identity_version == 'v3':
245 roles_to_assign = ['member']
Adam Youngb226f8e2016-06-25 21:41:36 -0400246 try:
Martin Kopec99d4dae2020-05-27 10:33:17 +0000247 self.creds_client.create_user_role('member')
Adam Youngb226f8e2016-06-25 21:41:36 -0400248 except lib_exc.Conflict:
Martin Kopec99d4dae2020-05-27 10:33:17 +0000249 LOG.warning('member role already exists, ignoring conflict.')
Colleen Murphy06374e22019-10-02 14:28:22 -0700250 for role in roles_to_assign:
251 if scope == 'project':
252 self.creds_client.assign_user_role(user, project, role)
253 elif scope == 'domain':
254 self.creds_client.assign_user_role_on_domain(
255 user, role, domain)
256 elif scope == 'system':
257 self.creds_client.assign_user_role_on_system(user, role)
Ghanshyam Mannf97c5cc2021-02-16 12:16:10 -0600258 LOG.info("Roles assigned to the user %s are: %s",
259 user['id'], roles_to_assign)
Matthew Treinish32f98a42015-07-14 19:58:46 -0400260
Colleen Murphy06374e22019-10-02 14:28:22 -0700261 creds = self.creds_client.get_credentials(**cred_params)
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400262 return cred_provider.TestResources(creds)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500263
264 def _create_network_resources(self, tenant_id):
edannon6cc6fbc2016-05-03 11:56:12 +0300265 """The function creates network resources in the given tenant.
266
267 The function checks if network_resources class member is empty,
268 In case it is, it will create a network, a subnet and a router for
269 the tenant according to the given tenant id parameter.
270 Otherwise it will create a network resource according
271 to the values from network_resources dict.
272
273 :param tenant_id: The tenant id to create resources for.
274 :type tenant_id: str
275 :raises: InvalidConfiguration, Exception
276 :returns: network resources(network,subnet,router)
277 :rtype: tuple
278 """
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500279 network = None
280 subnet = None
281 router = None
Matthew Treinish9f756a02014-01-15 10:26:07 -0500282 # Make sure settings
283 if self.network_resources:
284 if self.network_resources['router']:
285 if (not self.network_resources['subnet'] or
286 not self.network_resources['network']):
Matthew Treinish4217a702016-10-07 17:27:11 -0400287 raise lib_exc.InvalidConfiguration(
Matthew Treinish9f756a02014-01-15 10:26:07 -0500288 'A router requires a subnet and network')
289 elif self.network_resources['subnet']:
290 if not self.network_resources['network']:
Matthew Treinish4217a702016-10-07 17:27:11 -0400291 raise lib_exc.InvalidConfiguration(
Matthew Treinish9f756a02014-01-15 10:26:07 -0500292 'A subnet requires a network')
293 elif self.network_resources['dhcp']:
Matthew Treinish4217a702016-10-07 17:27:11 -0400294 raise lib_exc.InvalidConfiguration('DHCP requires a subnet')
Matthew Treinish9f756a02014-01-15 10:26:07 -0500295
Matthew Treinish0650aed2016-10-07 16:36:46 -0400296 rand_name_root = data_utils.rand_name(
297 self.name, prefix=self.resource_prefix)
Matthew Treinish9f756a02014-01-15 10:26:07 -0500298 if not self.network_resources or self.network_resources['network']:
Matthew Treinish0650aed2016-10-07 16:36:46 -0400299 network_name = rand_name_root + "-network"
Matthew Treinish9f756a02014-01-15 10:26:07 -0500300 network = self._create_network(network_name, tenant_id)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500301 try:
Matthew Treinish9f756a02014-01-15 10:26:07 -0500302 if not self.network_resources or self.network_resources['subnet']:
Matthew Treinish0650aed2016-10-07 16:36:46 -0400303 subnet_name = rand_name_root + "-subnet"
Matthew Treinish9f756a02014-01-15 10:26:07 -0500304 subnet = self._create_subnet(subnet_name, tenant_id,
305 network['id'])
306 if not self.network_resources or self.network_resources['router']:
Matthew Treinish0650aed2016-10-07 16:36:46 -0400307 router_name = rand_name_root + "-router"
Matthew Treinish9f756a02014-01-15 10:26:07 -0500308 router = self._create_router(router_name, tenant_id)
309 self._add_router_interface(router['id'], subnet['id'])
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500310 except Exception:
Andrea Frittoli (andreaf)d9a18b02016-02-29 15:27:34 +0000311 try:
312 if router:
313 self._clear_isolated_router(router['id'], router['name'])
314 if subnet:
315 self._clear_isolated_subnet(subnet['id'], subnet['name'])
316 if network:
317 self._clear_isolated_network(network['id'],
318 network['name'])
319 except Exception as cleanup_exception:
320 msg = "There was an exception trying to setup network " \
321 "resources for tenant %s, and this error happened " \
322 "trying to clean them up: %s"
Jordan Pittier525ec712016-12-07 17:51:26 +0100323 LOG.warning(msg, tenant_id, cleanup_exception)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500324 raise
325 return network, subnet, router
326
327 def _create_network(self, name, tenant_id):
John Warren94d8faf2015-09-15 12:22:24 -0400328 resp_body = self.networks_admin_client.create_network(
Andrea Frittoliae9aca02014-09-25 11:43:11 +0100329 name=name, tenant_id=tenant_id)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500330 return resp_body['network']
331
332 def _create_subnet(self, subnet_name, tenant_id, network_id):
Matthew Treinish75abbcf2016-10-07 16:19:12 -0400333 base_cidr = netaddr.IPNetwork(self.project_network_cidr)
334 mask_bits = self.project_network_mask_bits
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500335 for subnet_cidr in base_cidr.subnet(mask_bits):
336 try:
Andrea Frittoliae9aca02014-09-25 11:43:11 +0100337 if self.network_resources:
John Warren3961acd2015-10-02 14:38:53 -0400338 resp_body = self.subnets_admin_client.\
Andrea Frittoliae9aca02014-09-25 11:43:11 +0100339 create_subnet(
340 network_id=network_id, cidr=str(subnet_cidr),
341 name=subnet_name,
342 tenant_id=tenant_id,
343 enable_dhcp=self.network_resources['dhcp'],
zhongjun5b68f502017-07-04 15:28:05 +0800344 ip_version=(ipaddress.ip_network(
likui19b70a32020-12-02 13:25:18 +0800345 str(subnet_cidr)).version))
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500346 else:
John Warren3961acd2015-10-02 14:38:53 -0400347 resp_body = self.subnets_admin_client.\
Andrea Frittoliae9aca02014-09-25 11:43:11 +0100348 create_subnet(network_id=network_id,
349 cidr=str(subnet_cidr),
350 name=subnet_name,
351 tenant_id=tenant_id,
zhongjun5b68f502017-07-04 15:28:05 +0800352 ip_version=(ipaddress.ip_network(
likui19b70a32020-12-02 13:25:18 +0800353 str(subnet_cidr)).version))
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500354 break
Masayuki Igawa4b29e472015-02-16 10:41:54 +0900355 except lib_exc.BadRequest as e:
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500356 if 'overlaps with another subnet' not in str(e):
357 raise
358 else:
David Kranzd4210412014-11-21 08:37:45 -0500359 message = 'Available CIDR for subnet creation could not be found'
360 raise Exception(message)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500361 return resp_body['subnet']
362
363 def _create_router(self, router_name, tenant_id):
zhufl6b7040a2017-01-18 16:38:34 +0800364 kwargs = {'name': router_name,
365 'tenant_id': tenant_id}
366 if self.public_network_id:
367 kwargs['external_gateway_info'] = dict(
368 network_id=self.public_network_id)
369 resp_body = self.routers_admin_client.create_router(**kwargs)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500370 return resp_body['router']
371
372 def _add_router_interface(self, router_id, subnet_id):
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000373 self.routers_admin_client.add_router_interface(router_id,
piyush11078694aca952015-12-17 12:54:44 +0530374 subnet_id=subnet_id)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500375
Colleen Murphy06374e22019-10-02 14:28:22 -0700376 def get_credentials(self, credential_type, scope=None):
377 if not scope and self._creds.get(str(credential_type)):
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700378 credentials = self._creds[str(credential_type)]
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600379 elif scope and (
380 self._creds.get("%s_%s" % (scope, str(credential_type)))):
381 credentials = self._creds["%s_%s" % (scope, str(credential_type))]
Matthew Treinishb86cda92013-07-29 11:22:23 -0400382 else:
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600383 LOG.debug("Creating new dynamic creds for scope: %s and "
384 "credential_type: %s", scope, credential_type)
Ghanshyam Mann7f394252021-01-29 13:07:23 -0600385 if scope:
Ghanshyam Mann420586c2021-01-29 13:23:18 -0600386 if credential_type in [['admin'], ['alt_admin']]:
Ghanshyam Mann7f394252021-01-29 13:07:23 -0600387 credentials = self._create_creds(
388 admin=True, scope=scope)
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600389 elif credential_type in [['alt_member'], ['alt_reader']]:
390 cred_type = credential_type[0][4:]
Lance Bragstadef13f402021-03-04 17:12:10 +0000391 if isinstance(cred_type, str):
392 cred_type = [cred_type]
Ghanshyam Mann7f394252021-01-29 13:07:23 -0600393 credentials = self._create_creds(
Lance Bragstadef13f402021-03-04 17:12:10 +0000394 roles=cred_type, scope=scope)
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600395 else:
396 credentials = self._create_creds(
397 roles=credential_type, scope=scope)
Ghanshyam Mann7f394252021-01-29 13:07:23 -0600398 elif credential_type in ['primary', 'alt', 'admin']:
Matthew Treinish976e8df2014-12-19 14:21:54 -0500399 is_admin = (credential_type == 'admin')
400 credentials = self._create_creds(admin=is_admin)
401 else:
Ghanshyam Mann7f394252021-01-29 13:07:23 -0600402 credentials = self._create_creds(roles=credential_type)
Colleen Murphy06374e22019-10-02 14:28:22 -0700403 if scope:
404 self._creds["%s_%s" %
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600405 (scope, str(credential_type))] = credentials
Colleen Murphy06374e22019-10-02 14:28:22 -0700406 else:
407 self._creds[str(credential_type)] = credentials
Andrea Frittolifc315902014-03-20 09:21:44 +0000408 # Maintained until tests are ported
Federico Ressi2d6bcaa2018-04-11 12:37:36 +0200409 LOG.info("Acquired dynamic creds:\n"
410 " credentials: %s", credentials)
411 if (self.neutron_available and self.create_networks):
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500412 network, subnet, router = self._create_network_resources(
Andrea Frittolifc315902014-03-20 09:21:44 +0000413 credentials.tenant_id)
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400414 credentials.set_resources(network=network, subnet=subnet,
415 router=router)
Federico Ressi2d6bcaa2018-04-11 12:37:36 +0200416 LOG.info("Created isolated network resources for:\n"
417 " credentials: %s", credentials)
Andrea Frittoli9612e812014-03-13 10:57:26 +0000418 return credentials
Matthew Treinishb86cda92013-07-29 11:22:23 -0400419
Ghanshyam Mann32e05572021-01-29 11:24:56 -0600420 # TODO(gmann): Remove this method in favor of get_project_member_creds()
421 # after the deprecation phase.
Andrea Frittoli9612e812014-03-13 10:57:26 +0000422 def get_primary_creds(self):
423 return self.get_credentials('primary')
Matthew Treinishb86cda92013-07-29 11:22:23 -0400424
Ghanshyam Mann32e05572021-01-29 11:24:56 -0600425 # TODO(gmann): Remove this method in favor of get_project_admin_creds()
426 # after the deprecation phase.
Andrea Frittoli9612e812014-03-13 10:57:26 +0000427 def get_admin_creds(self):
428 return self.get_credentials('admin')
Andrea Frittolifc315902014-03-20 09:21:44 +0000429
Ghanshyam Mann32e05572021-01-29 11:24:56 -0600430 # TODO(gmann): Replace this method with more appropriate name.
431 # like get_project_alt_member_creds()
Andrea Frittoli9612e812014-03-13 10:57:26 +0000432 def get_alt_creds(self):
433 return self.get_credentials('alt')
Matthew Treinishb86cda92013-07-29 11:22:23 -0400434
Colleen Murphy06374e22019-10-02 14:28:22 -0700435 def get_system_admin_creds(self):
436 return self.get_credentials(['admin'], scope='system')
437
438 def get_system_member_creds(self):
439 return self.get_credentials(['member'], scope='system')
440
441 def get_system_reader_creds(self):
442 return self.get_credentials(['reader'], scope='system')
443
444 def get_domain_admin_creds(self):
445 return self.get_credentials(['admin'], scope='domain')
446
447 def get_domain_member_creds(self):
448 return self.get_credentials(['member'], scope='domain')
449
450 def get_domain_reader_creds(self):
451 return self.get_credentials(['reader'], scope='domain')
452
453 def get_project_admin_creds(self):
454 return self.get_credentials(['admin'], scope='project')
455
Ghanshyam Mann420586c2021-01-29 13:23:18 -0600456 def get_project_alt_admin_creds(self):
457 return self.get_credentials(['alt_admin'], scope='project')
458
Colleen Murphy06374e22019-10-02 14:28:22 -0700459 def get_project_member_creds(self):
460 return self.get_credentials(['member'], scope='project')
461
Ghanshyam Mann420586c2021-01-29 13:23:18 -0600462 def get_project_alt_member_creds(self):
463 return self.get_credentials(['alt_member'], scope='project')
464
Colleen Murphy06374e22019-10-02 14:28:22 -0700465 def get_project_reader_creds(self):
466 return self.get_credentials(['reader'], scope='project')
467
Ghanshyam Mann420586c2021-01-29 13:23:18 -0600468 def get_project_alt_reader_creds(self):
469 return self.get_credentials(['alt_reader'], scope='project')
470
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600471 def get_creds_by_roles(self, roles, force_new=False, scope=None):
Matthew Treinish976e8df2014-12-19 14:21:54 -0500472 roles = list(set(roles))
473 # The roles list as a str will become the index as the dict key for
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700474 # the created credentials set in the dynamic_creds dict.
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600475 creds_name = str(roles)
476 if scope:
477 creds_name = "%s_%s" % (scope, str(roles))
478 exist_creds = self._creds.get(creds_name)
Matthew Treinish976e8df2014-12-19 14:21:54 -0500479 # If force_new flag is True 2 cred sets with the same roles are needed
480 # handle this by creating a separate index for old one to store it
481 # separately for cleanup
482 if exist_creds and force_new:
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600483 new_index = creds_name + '-' + str(len(self._creds))
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700484 self._creds[new_index] = exist_creds
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600485 del self._creds[creds_name]
486 return self.get_credentials(roles, scope=scope)
Matthew Treinish976e8df2014-12-19 14:21:54 -0500487
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500488 def _clear_isolated_router(self, router_id, router_name):
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000489 client = self.routers_admin_client
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500490 try:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000491 client.delete_router(router_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900492 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100493 LOG.warning('router with name: %s not found for delete',
zhangguoqing6c096642016-01-04 06:17:21 +0000494 router_name)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500495
496 def _clear_isolated_subnet(self, subnet_id, subnet_name):
John Warren3961acd2015-10-02 14:38:53 -0400497 client = self.subnets_admin_client
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500498 try:
John Warren3961acd2015-10-02 14:38:53 -0400499 client.delete_subnet(subnet_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900500 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100501 LOG.warning('subnet with name: %s not found for delete',
zhangguoqing6c096642016-01-04 06:17:21 +0000502 subnet_name)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500503
504 def _clear_isolated_network(self, network_id, network_name):
John Warren94d8faf2015-09-15 12:22:24 -0400505 net_client = self.networks_admin_client
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500506 try:
507 net_client.delete_network(network_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900508 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100509 LOG.warning('network with name: %s not found for delete',
zhangguoqing6c096642016-01-04 06:17:21 +0000510 network_name)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500511
Ala Rezmerita846eb7c2014-03-10 09:06:03 +0100512 def _cleanup_default_secgroup(self, tenant):
John Warrenf9606e92015-12-10 12:12:42 -0500513 nsg_client = self.security_groups_admin_client
514 resp_body = nsg_client.list_security_groups(tenant_id=tenant,
David Kranz34e88122014-12-11 15:24:05 -0500515 name="default")
Ala Rezmerita846eb7c2014-03-10 09:06:03 +0100516 secgroups_to_delete = resp_body['security_groups']
517 for secgroup in secgroups_to_delete:
518 try:
John Warrenf9606e92015-12-10 12:12:42 -0500519 nsg_client.delete_security_group(secgroup['id'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900520 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100521 LOG.warning('Security group %s, id %s not found for clean-up',
522 secgroup['name'], secgroup['id'])
Ala Rezmerita846eb7c2014-03-10 09:06:03 +0100523
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500524 def _clear_isolated_net_resources(self):
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000525 client = self.routers_admin_client
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700526 for cred in self._creds:
527 creds = self._creds.get(cred)
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400528 if (not creds or not any([creds.router, creds.network,
529 creds.subnet])):
530 continue
Salvatore Orlandocf996c62014-01-30 09:15:18 -0800531 LOG.debug("Clearing network: %(network)s, "
Matthew Treinishfe094ea2014-12-09 01:19:27 +0000532 "subnet: %(subnet)s, router: %(router)s",
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400533 {'network': creds.network, 'subnet': creds.subnet,
534 'router': creds.router})
Salvatore Orlandocf996c62014-01-30 09:15:18 -0800535 if (not self.network_resources or
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400536 (self.network_resources.get('router') and creds.subnet)):
Matthew Treinish9f756a02014-01-15 10:26:07 -0500537 try:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000538 client.remove_router_interface(
piyush11078694aca952015-12-17 12:54:44 +0530539 creds.router['id'],
540 subnet_id=creds.subnet['id'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900541 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100542 LOG.warning('router with name: %s not found for delete',
zhangguoqing6c096642016-01-04 06:17:21 +0000543 creds.router['name'])
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400544 self._clear_isolated_router(creds.router['id'],
545 creds.router['name'])
Salvatore Orlandocf996c62014-01-30 09:15:18 -0800546 if (not self.network_resources or
Salvatore Orlandocf996c62014-01-30 09:15:18 -0800547 self.network_resources.get('subnet')):
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400548 self._clear_isolated_subnet(creds.subnet['id'],
549 creds.subnet['name'])
Salvatore Orlandocf996c62014-01-30 09:15:18 -0800550 if (not self.network_resources or
551 self.network_resources.get('network')):
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400552 self._clear_isolated_network(creds.network['id'],
553 creds.network['name'])
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500554
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700555 def clear_creds(self):
556 if not self._creds:
Matthew Treinishb86cda92013-07-29 11:22:23 -0400557 return
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500558 self._clear_isolated_net_resources()
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700559 for creds in six.itervalues(self._creds):
Matthew Treinishb86cda92013-07-29 11:22:23 -0400560 try:
Andrea Frittolic3280152015-02-26 12:42:34 +0000561 self.creds_client.delete_user(creds.user_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900562 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100563 LOG.warning("user with name: %s not found for delete",
zhangguoqing6c096642016-01-04 06:17:21 +0000564 creds.username)
zhufl2344ea62016-06-01 14:44:00 +0800565 # NOTE(zhufl): Only when neutron's security_group ext is
566 # enabled, _cleanup_default_secgroup will not raise error. But
Andrea Frittolicd368412017-08-14 21:37:56 +0100567 # here cannot use test_utils.is_extension_enabled for it will cause
zhufl2344ea62016-06-01 14:44:00 +0800568 # "circular dependency". So here just use try...except to
569 # ensure tenant deletion without big changes.
Matthew Treinishb86cda92013-07-29 11:22:23 -0400570 try:
Matthew Treinish75abbcf2016-10-07 16:19:12 -0400571 if self.neutron_available:
Andrea Frittolic3280152015-02-26 12:42:34 +0000572 self._cleanup_default_secgroup(creds.tenant_id)
zhufl2344ea62016-06-01 14:44:00 +0800573 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100574 LOG.warning("failed to cleanup tenant %s's secgroup",
zhufl2344ea62016-06-01 14:44:00 +0800575 creds.tenant_name)
576 try:
Andrea Frittolic3280152015-02-26 12:42:34 +0000577 self.creds_client.delete_project(creds.tenant_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900578 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100579 LOG.warning("tenant with name: %s not found for delete",
zhangguoqing6c096642016-01-04 06:17:21 +0000580 creds.tenant_name)
Colleen Murphy06374e22019-10-02 14:28:22 -0700581
582 # if cred is domain scoped, delete ephemeral domain
583 # do not delete default domain
584 if (hasattr(creds, 'domain_id') and
585 creds.domain_id != creds.project_domain_id):
586 try:
587 self.creds_client.delete_domain(creds.domain_id)
588 except lib_exc.NotFound:
589 LOG.warning("domain with name: %s not found for delete",
590 creds.domain_name)
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700591 self._creds = {}
Andrea Frittoli8283b4e2014-07-17 13:28:58 +0100592
593 def is_multi_user(self):
594 return True
Yair Fried76488d72014-10-21 10:13:19 +0300595
596 def is_multi_tenant(self):
597 return True
Matthew Treinish4a596932015-03-06 20:37:01 -0500598
599 def is_role_available(self, role):
600 return True