blob: 99647d49ce30acc45e86fbce4951a8b0831d0c95 [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
Miguel Lavalleb8fabc52013-08-23 11:19:57 -050019
Matthew Treinish3787e4c2016-10-07 21:25:33 -040020from tempest.lib.common import cred_client
Matthew Treinish00ab6be2016-10-07 16:29:18 -040021from tempest.lib.common import cred_provider
Matthew Treinish0650aed2016-10-07 16:36:46 -040022from tempest.lib.common.utils import data_utils
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050023from tempest.lib import exceptions as lib_exc
Andrea Frittolidcd91002017-07-18 11:34:13 +010024from tempest.lib.services import clients
Matthew Treinishb86cda92013-07-29 11:22:23 -040025
26LOG = logging.getLogger(__name__)
27
28
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -070029class DynamicCredentialProvider(cred_provider.CredentialProvider):
Masayuki Igawaa1c3af32017-09-07 10:22:37 +090030 """Creates credentials dynamically for tests
31
32 A credential provider that, based on an initial set of
33 admin credentials, creates new credentials on the fly for
34 tests to use and then discard.
35
36 :param str identity_version: identity API version to use `v2` or `v3`
37 :param str admin_role: name of the admin role added to admin users
38 :param str name: names of dynamic resources include this parameter
39 when specified
40 :param str credentials_domain: name of the domain where the users
41 are created. If not defined, the project
42 domain from admin_credentials is used
43 :param dict network_resources: network resources to be created for
44 the created credentials
45 :param Credentials admin_creds: initial admin credentials
46 :param bool identity_admin_domain_scope: Set to true if admin should be
47 scoped to the domain. By
48 default this is False and the
49 admin role is scoped to the
50 project.
51 :param str identity_admin_role: The role name to use for admin
52 :param list extra_roles: A list of strings for extra roles that should
53 be assigned to all created users
54 :param bool neutron_available: Whether we are running in an environemnt
55 with neutron
56 :param bool create_networks: Whether dynamic project networks should be
57 created or not
58 :param project_network_cidr: The CIDR to use for created project
59 networks
60 :param project_network_mask_bits: The network mask bits to use for
61 created project networks
62 :param public_network_id: The id for the public network to use
63 :param identity_admin_endpoint_type: The endpoint type for identity
64 admin clients. Defaults to public.
65 :param identity_uri: Identity URI of the target cloud
66 """
Matthew Treinishb86cda92013-07-29 11:22:23 -040067
Andrea Frittoli (andreaf)1eb04962015-10-09 14:48:06 +010068 def __init__(self, identity_version, name=None, network_resources=None,
Matthew Treinish75abbcf2016-10-07 16:19:12 -040069 credentials_domain=None, admin_role=None, admin_creds=None,
70 identity_admin_domain_scope=False,
71 identity_admin_role='admin', extra_roles=None,
72 neutron_available=False, create_networks=True,
73 project_network_cidr=None, project_network_mask_bits=None,
Andrea Frittolidcd91002017-07-18 11:34:13 +010074 public_network_id=None, resource_prefix=None,
75 identity_admin_endpoint_type='public', identity_uri=None):
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -070076 super(DynamicCredentialProvider, self).__init__(
Andrea Frittolidcd91002017-07-18 11:34:13 +010077 identity_version=identity_version, identity_uri=identity_uri,
78 admin_role=admin_role, name=name,
79 credentials_domain=credentials_domain,
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +010080 network_resources=network_resources)
81 self.network_resources = network_resources
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -070082 self._creds = {}
Miguel Lavalleb8fabc52013-08-23 11:19:57 -050083 self.ports = []
Matthew Treinish0650aed2016-10-07 16:36:46 -040084 self.resource_prefix = resource_prefix or ''
Matthew Treinish75abbcf2016-10-07 16:19:12 -040085 self.neutron_available = neutron_available
86 self.create_networks = create_networks
87 self.project_network_cidr = project_network_cidr
88 self.project_network_mask_bits = project_network_mask_bits
89 self.public_network_id = public_network_id
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +010090 self.default_admin_creds = admin_creds
Matthew Treinish75abbcf2016-10-07 16:19:12 -040091 self.identity_admin_domain_scope = identity_admin_domain_scope
92 self.identity_admin_role = identity_admin_role or 'admin'
Andrea Frittolidcd91002017-07-18 11:34:13 +010093 self.identity_admin_endpoint_type = identity_admin_endpoint_type
Matthew Treinish75abbcf2016-10-07 16:19:12 -040094 self.extra_roles = extra_roles or []
Yaroslav Lobankov47a93ab2016-02-07 16:32:49 -060095 (self.identity_admin_client,
96 self.tenants_admin_client,
Daniel Mellado82c83a52015-12-09 15:16:49 +000097 self.users_admin_client,
Daniel Mellado7aea5342016-02-09 09:10:12 +000098 self.roles_admin_client,
Daniel Mellado91a26b62016-02-11 11:13:04 +000099 self.domains_admin_client,
John Warren3961acd2015-10-02 14:38:53 -0400100 self.networks_admin_client,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000101 self.routers_admin_client,
John Warren49c0fe52015-10-22 12:35:54 -0400102 self.subnets_admin_client,
John Warrenf9606e92015-12-10 12:12:42 -0500103 self.ports_admin_client,
Andrea Frittolidcd91002017-07-18 11:34:13 +0100104 self.security_groups_admin_client) = self._get_admin_clients(
105 identity_admin_endpoint_type)
John Warren3961acd2015-10-02 14:38:53 -0400106 # Domain where isolated credentials are provisioned (v3 only).
Andrea Frittolic3280152015-02-26 12:42:34 +0000107 # Use that of the admin account is None is configured.
108 self.creds_domain_name = None
109 if self.identity_version == 'v3':
110 self.creds_domain_name = (
David Kranz87fc7e92015-07-28 14:05:20 -0400111 self.default_admin_creds.project_domain_name or
Andrea Frittoli (andreaf)1eb04962015-10-09 14:48:06 +0100112 self.credentials_domain)
Jamie Lennox15350172015-08-17 10:54:25 +1000113 self.creds_client = cred_client.get_creds_client(
Daniel Melladob04da902015-11-20 17:43:12 +0100114 self.identity_admin_client,
115 self.tenants_admin_client,
Daniel Mellado82c83a52015-12-09 15:16:49 +0000116 self.users_admin_client,
Daniel Mellado7aea5342016-02-09 09:10:12 +0000117 self.roles_admin_client,
Daniel Mellado91a26b62016-02-11 11:13:04 +0000118 self.domains_admin_client,
Daniel Melladob04da902015-11-20 17:43:12 +0100119 self.creds_domain_name)
Matthew Treinishb86cda92013-07-29 11:22:23 -0400120
Andrea Frittolidcd91002017-07-18 11:34:13 +0100121 def _get_admin_clients(self, endpoint_type):
Ken'ichi Ohmichicb67d2d2015-11-19 08:23:22 +0000122 """Returns a tuple with instances of the following admin clients
123
124 (in this order):
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500125 identity
126 network
Matthew Treinishb86cda92013-07-29 11:22:23 -0400127 """
Andrea Frittolidcd91002017-07-18 11:34:13 +0100128 os = clients.ServiceClients(self.default_admin_creds,
129 self.identity_uri)
130 params = {'endpoint_type': endpoint_type}
Andrea Frittolic3280152015-02-26 12:42:34 +0000131 if self.identity_version == 'v2':
Andrea Frittolidcd91002017-07-18 11:34:13 +0100132 return (os.identity_v2.IdentityClient(**params),
133 os.identity_v2.TenantsClient(**params),
134 os.identity_v2.UsersClient(**params),
135 os.identity_v2.RolesClient(**params), None,
136 os.network.NetworksClient(),
137 os.network.RoutersClient(),
138 os.network.SubnetsClient(),
139 os.network.PortsClient(),
140 os.network.SecurityGroupsClient())
Andrea Frittolic3280152015-02-26 12:42:34 +0000141 else:
Andrea Frittoli (andreaf)100d18d2016-05-05 23:34:52 +0100142 # We use a dedicated client manager for identity client in case we
143 # need a different token scope for them.
Colleen Murphycd0bbbd2019-10-01 16:18:36 -0700144 if self.default_admin_creds.system:
145 scope = 'system'
Martin Kopeca28849f2021-01-21 14:06:21 +0000146 elif (self.identity_admin_domain_scope and
147 (self.default_admin_creds.domain_id or
148 self.default_admin_creds.domain_name)):
Colleen Murphycd0bbbd2019-10-01 16:18:36 -0700149 scope = 'domain'
150 else:
151 scope = 'project'
Andrea Frittolidcd91002017-07-18 11:34:13 +0100152 identity_os = clients.ServiceClients(self.default_admin_creds,
153 self.identity_uri,
154 scope=scope)
155 return (identity_os.identity_v3.IdentityClient(**params),
156 identity_os.identity_v3.ProjectsClient(**params),
157 identity_os.identity_v3.UsersClient(**params),
158 identity_os.identity_v3.RolesClient(**params),
159 identity_os.identity_v3.DomainsClient(**params),
160 os.network.NetworksClient(),
161 os.network.RoutersClient(),
162 os.network.SubnetsClient(),
163 os.network.PortsClient(),
164 os.network.SecurityGroupsClient())
Matthew Treinishb86cda92013-07-29 11:22:23 -0400165
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600166 def _create_creds(self, admin=False, roles=None, scope='project',
167 project_id=None):
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'.
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600181 :param str project_id: The project id of already created project
182 for credentials under same project.
Genadi Chereshnya88ea9ab2016-05-15 14:47:07 +0300183 :return: Readonly Credentials with network resources
Colleen Murphy06374e22019-10-02 14:28:22 -0700184 :raises: Exception if scope is invalid
Sean Dague6969b902014-01-28 06:48:37 -0500185 """
Colleen Murphy06374e22019-10-02 14:28:22 -0700186 if not roles:
187 roles = []
Genadi Chereshnya88ea9ab2016-05-15 14:47:07 +0300188 root = self.name
Sean Dague6969b902014-01-28 06:48:37 -0500189
Colleen Murphy06374e22019-10-02 14:28:22 -0700190 cred_params = {
191 'project': None,
192 'domain': None,
193 'system': None
194 }
195 if scope == 'project':
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600196 if not project_id:
197 project_name = data_utils.rand_name(
198 root, prefix=self.resource_prefix)
199 project_desc = project_name + '-desc'
200 project = self.creds_client.create_project(
201 name=project_name, description=project_desc)
202 else:
203 # NOTE(gmann) This is the case where creds are requested
204 # from the existing creds within same project. We should
205 # not create the new project in this case.
206 project = self.creds_client.show_project(project_id)
207 project_name = project['name']
208 LOG.info("Using the existing project %s for scope %s and "
209 "roles: %s", project['id'], scope, roles)
Colleen Murphy06374e22019-10-02 14:28:22 -0700210 # NOTE(andreaf) User and project can be distinguished from the
211 # context, having the same ID in both makes it easier to match them
212 # and debug.
213 username = project_name + '-project'
214 cred_params['project'] = project
215 elif scope == 'domain':
216 domain_name = data_utils.rand_name(
217 root, prefix=self.resource_prefix)
218 domain_desc = domain_name + '-desc'
219 domain = self.creds_client.create_domain(
220 name=domain_name, description=domain_desc)
221 username = domain_name + '-domain'
222 cred_params['domain'] = domain
223 elif scope == 'system':
224 prefix = data_utils.rand_name(root, prefix=self.resource_prefix)
225 username = prefix + '-system'
226 cred_params['system'] = 'all'
227 else:
228 raise lib_exc.InvalidScopeType(scope=scope)
Matthew Treinishb86cda92013-07-29 11:22:23 -0400229 if admin:
Colleen Murphy06374e22019-10-02 14:28:22 -0700230 username += '-admin'
231 elif roles and len(roles) == 1:
232 username += '-' + roles[0]
233 user_password = data_utils.rand_password()
234 cred_params['password'] = user_password
235 user = self.creds_client.create_user(
236 username, user_password)
237 cred_params['user'] = user
238 roles_to_assign = [r for r in roles]
239 if admin:
240 roles_to_assign.append(self.admin_role)
Lance Bragstadef13f402021-03-04 17:12:10 +0000241 if scope == 'project':
242 self.creds_client.assign_user_role(
243 user, project, self.identity_admin_role)
Andrea Frittoli (andreaf)100d18d2016-05-05 23:34:52 +0100244 if (self.identity_version == 'v3' and
Matthew Treinish75abbcf2016-10-07 16:19:12 -0400245 self.identity_admin_domain_scope):
Andrea Frittoli (andreaf)4bee2e72015-09-22 13:06:18 +0100246 self.creds_client.assign_user_role_on_domain(
Matthew Treinish75abbcf2016-10-07 16:19:12 -0400247 user, self.identity_admin_role)
Matthew Treinish976e8df2014-12-19 14:21:54 -0500248 # Add roles specified in config file
Colleen Murphy06374e22019-10-02 14:28:22 -0700249 roles_to_assign.extend(self.extra_roles)
250 # If there are still no roles, default to 'member'
Matthew Treinish32f98a42015-07-14 19:58:46 -0400251 # NOTE(mtreinish) For a user to have access to a project with v3 auth
252 # it must beassigned a role on the project. So we need to ensure that
253 # our newly created user has a role on the newly created project.
Colleen Murphy06374e22019-10-02 14:28:22 -0700254 if not roles_to_assign and self.identity_version == 'v3':
255 roles_to_assign = ['member']
Adam Youngb226f8e2016-06-25 21:41:36 -0400256 try:
Martin Kopec99d4dae2020-05-27 10:33:17 +0000257 self.creds_client.create_user_role('member')
Adam Youngb226f8e2016-06-25 21:41:36 -0400258 except lib_exc.Conflict:
Martin Kopec99d4dae2020-05-27 10:33:17 +0000259 LOG.warning('member role already exists, ignoring conflict.')
Colleen Murphy06374e22019-10-02 14:28:22 -0700260 for role in roles_to_assign:
261 if scope == 'project':
262 self.creds_client.assign_user_role(user, project, role)
263 elif scope == 'domain':
264 self.creds_client.assign_user_role_on_domain(
265 user, role, domain)
266 elif scope == 'system':
267 self.creds_client.assign_user_role_on_system(user, role)
Ghanshyam Mannc67b0262021-07-16 15:36:27 -0500268 LOG.info("Dynamic test user %s is created with scope %s and roles: %s",
269 user['id'], scope, roles_to_assign)
Matthew Treinish32f98a42015-07-14 19:58:46 -0400270
Colleen Murphy06374e22019-10-02 14:28:22 -0700271 creds = self.creds_client.get_credentials(**cred_params)
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400272 return cred_provider.TestResources(creds)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500273
274 def _create_network_resources(self, tenant_id):
edannon6cc6fbc2016-05-03 11:56:12 +0300275 """The function creates network resources in the given tenant.
276
277 The function checks if network_resources class member is empty,
278 In case it is, it will create a network, a subnet and a router for
279 the tenant according to the given tenant id parameter.
280 Otherwise it will create a network resource according
281 to the values from network_resources dict.
282
283 :param tenant_id: The tenant id to create resources for.
284 :type tenant_id: str
285 :raises: InvalidConfiguration, Exception
286 :returns: network resources(network,subnet,router)
287 :rtype: tuple
288 """
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500289 network = None
290 subnet = None
291 router = None
Matthew Treinish9f756a02014-01-15 10:26:07 -0500292 # Make sure settings
293 if self.network_resources:
294 if self.network_resources['router']:
295 if (not self.network_resources['subnet'] or
296 not self.network_resources['network']):
Matthew Treinish4217a702016-10-07 17:27:11 -0400297 raise lib_exc.InvalidConfiguration(
Matthew Treinish9f756a02014-01-15 10:26:07 -0500298 'A router requires a subnet and network')
299 elif self.network_resources['subnet']:
300 if not self.network_resources['network']:
Matthew Treinish4217a702016-10-07 17:27:11 -0400301 raise lib_exc.InvalidConfiguration(
Matthew Treinish9f756a02014-01-15 10:26:07 -0500302 'A subnet requires a network')
303 elif self.network_resources['dhcp']:
Matthew Treinish4217a702016-10-07 17:27:11 -0400304 raise lib_exc.InvalidConfiguration('DHCP requires a subnet')
Matthew Treinish9f756a02014-01-15 10:26:07 -0500305
Matthew Treinish0650aed2016-10-07 16:36:46 -0400306 rand_name_root = data_utils.rand_name(
307 self.name, prefix=self.resource_prefix)
Matthew Treinish9f756a02014-01-15 10:26:07 -0500308 if not self.network_resources or self.network_resources['network']:
Matthew Treinish0650aed2016-10-07 16:36:46 -0400309 network_name = rand_name_root + "-network"
Matthew Treinish9f756a02014-01-15 10:26:07 -0500310 network = self._create_network(network_name, tenant_id)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500311 try:
Matthew Treinish9f756a02014-01-15 10:26:07 -0500312 if not self.network_resources or self.network_resources['subnet']:
Matthew Treinish0650aed2016-10-07 16:36:46 -0400313 subnet_name = rand_name_root + "-subnet"
Matthew Treinish9f756a02014-01-15 10:26:07 -0500314 subnet = self._create_subnet(subnet_name, tenant_id,
315 network['id'])
316 if not self.network_resources or self.network_resources['router']:
Matthew Treinish0650aed2016-10-07 16:36:46 -0400317 router_name = rand_name_root + "-router"
Matthew Treinish9f756a02014-01-15 10:26:07 -0500318 router = self._create_router(router_name, tenant_id)
319 self._add_router_interface(router['id'], subnet['id'])
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500320 except Exception:
Andrea Frittoli (andreaf)d9a18b02016-02-29 15:27:34 +0000321 try:
322 if router:
323 self._clear_isolated_router(router['id'], router['name'])
324 if subnet:
325 self._clear_isolated_subnet(subnet['id'], subnet['name'])
326 if network:
327 self._clear_isolated_network(network['id'],
328 network['name'])
329 except Exception as cleanup_exception:
330 msg = "There was an exception trying to setup network " \
331 "resources for tenant %s, and this error happened " \
332 "trying to clean them up: %s"
Jordan Pittier525ec712016-12-07 17:51:26 +0100333 LOG.warning(msg, tenant_id, cleanup_exception)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500334 raise
335 return network, subnet, router
336
337 def _create_network(self, name, tenant_id):
John Warren94d8faf2015-09-15 12:22:24 -0400338 resp_body = self.networks_admin_client.create_network(
Andrea Frittoliae9aca02014-09-25 11:43:11 +0100339 name=name, tenant_id=tenant_id)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500340 return resp_body['network']
341
342 def _create_subnet(self, subnet_name, tenant_id, network_id):
Matthew Treinish75abbcf2016-10-07 16:19:12 -0400343 base_cidr = netaddr.IPNetwork(self.project_network_cidr)
344 mask_bits = self.project_network_mask_bits
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500345 for subnet_cidr in base_cidr.subnet(mask_bits):
346 try:
Andrea Frittoliae9aca02014-09-25 11:43:11 +0100347 if self.network_resources:
John Warren3961acd2015-10-02 14:38:53 -0400348 resp_body = self.subnets_admin_client.\
Andrea Frittoliae9aca02014-09-25 11:43:11 +0100349 create_subnet(
350 network_id=network_id, cidr=str(subnet_cidr),
351 name=subnet_name,
352 tenant_id=tenant_id,
353 enable_dhcp=self.network_resources['dhcp'],
zhongjun5b68f502017-07-04 15:28:05 +0800354 ip_version=(ipaddress.ip_network(
likui19b70a32020-12-02 13:25:18 +0800355 str(subnet_cidr)).version))
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500356 else:
John Warren3961acd2015-10-02 14:38:53 -0400357 resp_body = self.subnets_admin_client.\
Andrea Frittoliae9aca02014-09-25 11:43:11 +0100358 create_subnet(network_id=network_id,
359 cidr=str(subnet_cidr),
360 name=subnet_name,
361 tenant_id=tenant_id,
zhongjun5b68f502017-07-04 15:28:05 +0800362 ip_version=(ipaddress.ip_network(
likui19b70a32020-12-02 13:25:18 +0800363 str(subnet_cidr)).version))
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500364 break
Masayuki Igawa4b29e472015-02-16 10:41:54 +0900365 except lib_exc.BadRequest as e:
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500366 if 'overlaps with another subnet' not in str(e):
367 raise
368 else:
David Kranzd4210412014-11-21 08:37:45 -0500369 message = 'Available CIDR for subnet creation could not be found'
370 raise Exception(message)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500371 return resp_body['subnet']
372
373 def _create_router(self, router_name, tenant_id):
zhufl6b7040a2017-01-18 16:38:34 +0800374 kwargs = {'name': router_name,
375 'tenant_id': tenant_id}
376 if self.public_network_id:
377 kwargs['external_gateway_info'] = dict(
378 network_id=self.public_network_id)
379 resp_body = self.routers_admin_client.create_router(**kwargs)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500380 return resp_body['router']
381
382 def _add_router_interface(self, router_id, subnet_id):
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000383 self.routers_admin_client.add_router_interface(router_id,
piyush11078694aca952015-12-17 12:54:44 +0530384 subnet_id=subnet_id)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500385
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600386 def _get_project_id(self, credential_type, scope):
387 same_creds = [['admin'], ['member'], ['reader']]
388 same_alt_creds = [['alt_admin'], ['alt_member'], ['alt_reader']]
389 search_in = []
390 if credential_type in same_creds:
391 search_in = same_creds
392 elif credential_type in same_alt_creds:
393 search_in = same_alt_creds
394 for cred in search_in:
395 found_cred = self._creds.get("%s_%s" % (scope, str(cred)))
396 if found_cred:
397 project_id = found_cred.get("%s_%s" % (scope, 'id'))
398 LOG.debug("Reusing existing project %s from creds: %s ",
399 project_id, found_cred)
400 return project_id
401 return None
402
403 def get_credentials(self, credential_type, scope=None, by_role=False):
404 cred_prefix = ''
405 if by_role:
406 cred_prefix = 'role_'
407 if not scope and self._creds.get(
408 "%s%s" % (cred_prefix, str(credential_type))):
409 credentials = self._creds[
410 "%s%s" % (cred_prefix, str(credential_type))]
411 elif scope and (self._creds.get(
412 "%s%s_%s" % (cred_prefix, scope, str(credential_type)))):
413 credentials = self._creds[
414 "%s%s_%s" % (cred_prefix, scope, str(credential_type))]
Matthew Treinishb86cda92013-07-29 11:22:23 -0400415 else:
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600416 LOG.debug("Creating new dynamic creds for scope: %s and "
417 "credential_type: %s", scope, credential_type)
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600418 project_id = None
Ghanshyam Mann7f394252021-01-29 13:07:23 -0600419 if scope:
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600420 if scope == 'project':
421 project_id = self._get_project_id(
422 credential_type, 'project')
423 if by_role:
Ghanshyam Mann7f394252021-01-29 13:07:23 -0600424 credentials = self._create_creds(
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600425 roles=credential_type, scope=scope)
426 elif credential_type in [['admin'], ['alt_admin']]:
427 credentials = self._create_creds(
428 admin=True, scope=scope, project_id=project_id)
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600429 elif credential_type in [['alt_member'], ['alt_reader']]:
430 cred_type = credential_type[0][4:]
Lance Bragstadef13f402021-03-04 17:12:10 +0000431 if isinstance(cred_type, str):
432 cred_type = [cred_type]
Ghanshyam Mann7f394252021-01-29 13:07:23 -0600433 credentials = self._create_creds(
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600434 roles=cred_type, scope=scope, project_id=project_id)
435 elif credential_type in [['member'], ['reader']]:
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600436 credentials = self._create_creds(
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600437 roles=credential_type, scope=scope,
438 project_id=project_id)
Ghanshyam Mann7f394252021-01-29 13:07:23 -0600439 elif credential_type in ['primary', 'alt', 'admin']:
Matthew Treinish976e8df2014-12-19 14:21:54 -0500440 is_admin = (credential_type == 'admin')
441 credentials = self._create_creds(admin=is_admin)
442 else:
Ghanshyam Mann7f394252021-01-29 13:07:23 -0600443 credentials = self._create_creds(roles=credential_type)
Colleen Murphy06374e22019-10-02 14:28:22 -0700444 if scope:
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600445 self._creds["%s%s_%s" % (
446 cred_prefix, scope, str(credential_type))] = credentials
Colleen Murphy06374e22019-10-02 14:28:22 -0700447 else:
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600448 self._creds[
449 "%s%s" % (cred_prefix, str(credential_type))] = credentials
Andrea Frittolifc315902014-03-20 09:21:44 +0000450 # Maintained until tests are ported
Federico Ressi2d6bcaa2018-04-11 12:37:36 +0200451 LOG.info("Acquired dynamic creds:\n"
452 " credentials: %s", credentials)
Ghanshyam Mann5dcdd412021-06-25 11:50:03 -0500453 # NOTE(gmann): For 'domain' and 'system' scoped token, there is no
454 # project_id so we are skipping the network creation for both
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600455 # scope.
456 # We need to create nework resource once per project.
457 if (not project_id and (not scope or scope == 'project')):
Ghanshyam Mann5dcdd412021-06-25 11:50:03 -0500458 if (self.neutron_available and self.create_networks):
459 network, subnet, router = self._create_network_resources(
460 credentials.tenant_id)
461 credentials.set_resources(network=network, subnet=subnet,
462 router=router)
463 LOG.info("Created isolated network resources for:\n"
464 " credentials: %s", credentials)
465 else:
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600466 LOG.info("Network resources are not created for requested "
467 "scope: %s and credentials: %s", scope, credentials)
Andrea Frittoli9612e812014-03-13 10:57:26 +0000468 return credentials
Matthew Treinishb86cda92013-07-29 11:22:23 -0400469
Ghanshyam Mann32e05572021-01-29 11:24:56 -0600470 # TODO(gmann): Remove this method in favor of get_project_member_creds()
471 # after the deprecation phase.
Andrea Frittoli9612e812014-03-13 10:57:26 +0000472 def get_primary_creds(self):
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600473 return self.get_project_member_creds()
Matthew Treinishb86cda92013-07-29 11:22:23 -0400474
Andrea Frittoli9612e812014-03-13 10:57:26 +0000475 def get_admin_creds(self):
476 return self.get_credentials('admin')
Andrea Frittolifc315902014-03-20 09:21:44 +0000477
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600478 # TODO(gmann): Remove this method in favor of
479 # get_project_alt_member_creds() after the deprecation phase.
Andrea Frittoli9612e812014-03-13 10:57:26 +0000480 def get_alt_creds(self):
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600481 return self.get_project_alt_member_creds()
Matthew Treinishb86cda92013-07-29 11:22:23 -0400482
Colleen Murphy06374e22019-10-02 14:28:22 -0700483 def get_system_admin_creds(self):
484 return self.get_credentials(['admin'], scope='system')
485
486 def get_system_member_creds(self):
487 return self.get_credentials(['member'], scope='system')
488
489 def get_system_reader_creds(self):
490 return self.get_credentials(['reader'], scope='system')
491
492 def get_domain_admin_creds(self):
493 return self.get_credentials(['admin'], scope='domain')
494
495 def get_domain_member_creds(self):
496 return self.get_credentials(['member'], scope='domain')
497
498 def get_domain_reader_creds(self):
499 return self.get_credentials(['reader'], scope='domain')
500
501 def get_project_admin_creds(self):
502 return self.get_credentials(['admin'], scope='project')
503
Ghanshyam Mann420586c2021-01-29 13:23:18 -0600504 def get_project_alt_admin_creds(self):
505 return self.get_credentials(['alt_admin'], scope='project')
506
Colleen Murphy06374e22019-10-02 14:28:22 -0700507 def get_project_member_creds(self):
508 return self.get_credentials(['member'], scope='project')
509
Ghanshyam Mann420586c2021-01-29 13:23:18 -0600510 def get_project_alt_member_creds(self):
511 return self.get_credentials(['alt_member'], scope='project')
512
Colleen Murphy06374e22019-10-02 14:28:22 -0700513 def get_project_reader_creds(self):
514 return self.get_credentials(['reader'], scope='project')
515
Ghanshyam Mann420586c2021-01-29 13:23:18 -0600516 def get_project_alt_reader_creds(self):
517 return self.get_credentials(['alt_reader'], scope='project')
518
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600519 def get_creds_by_roles(self, roles, force_new=False, scope=None):
Matthew Treinish976e8df2014-12-19 14:21:54 -0500520 roles = list(set(roles))
521 # The roles list as a str will become the index as the dict key for
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700522 # the created credentials set in the dynamic_creds dict.
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600523 creds_name = "role_%s" % str(roles)
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600524 if scope:
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600525 creds_name = "role_%s_%s" % (scope, str(roles))
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600526 exist_creds = self._creds.get(creds_name)
Matthew Treinish976e8df2014-12-19 14:21:54 -0500527 # If force_new flag is True 2 cred sets with the same roles are needed
528 # handle this by creating a separate index for old one to store it
529 # separately for cleanup
530 if exist_creds and force_new:
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600531 new_index = creds_name + '-' + str(len(self._creds))
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700532 self._creds[new_index] = exist_creds
Ghanshyam Mann2d0da042021-03-05 09:09:30 -0600533 del self._creds[creds_name]
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600534 return self.get_credentials(roles, scope=scope, by_role=True)
Matthew Treinish976e8df2014-12-19 14:21:54 -0500535
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500536 def _clear_isolated_router(self, router_id, router_name):
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000537 client = self.routers_admin_client
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500538 try:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000539 client.delete_router(router_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900540 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100541 LOG.warning('router with name: %s not found for delete',
zhangguoqing6c096642016-01-04 06:17:21 +0000542 router_name)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500543
544 def _clear_isolated_subnet(self, subnet_id, subnet_name):
John Warren3961acd2015-10-02 14:38:53 -0400545 client = self.subnets_admin_client
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500546 try:
John Warren3961acd2015-10-02 14:38:53 -0400547 client.delete_subnet(subnet_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900548 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100549 LOG.warning('subnet with name: %s not found for delete',
zhangguoqing6c096642016-01-04 06:17:21 +0000550 subnet_name)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500551
552 def _clear_isolated_network(self, network_id, network_name):
John Warren94d8faf2015-09-15 12:22:24 -0400553 net_client = self.networks_admin_client
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500554 try:
555 net_client.delete_network(network_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900556 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100557 LOG.warning('network with name: %s not found for delete',
zhangguoqing6c096642016-01-04 06:17:21 +0000558 network_name)
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500559
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500560 def _clear_isolated_net_resources(self):
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000561 client = self.routers_admin_client
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700562 for cred in self._creds:
563 creds = self._creds.get(cred)
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400564 if (not creds or not any([creds.router, creds.network,
565 creds.subnet])):
566 continue
Salvatore Orlandocf996c62014-01-30 09:15:18 -0800567 LOG.debug("Clearing network: %(network)s, "
Matthew Treinishfe094ea2014-12-09 01:19:27 +0000568 "subnet: %(subnet)s, router: %(router)s",
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400569 {'network': creds.network, 'subnet': creds.subnet,
570 'router': creds.router})
Salvatore Orlandocf996c62014-01-30 09:15:18 -0800571 if (not self.network_resources or
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400572 (self.network_resources.get('router') and creds.subnet)):
Matthew Treinish9f756a02014-01-15 10:26:07 -0500573 try:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +0000574 client.remove_router_interface(
piyush11078694aca952015-12-17 12:54:44 +0530575 creds.router['id'],
576 subnet_id=creds.subnet['id'])
Masayuki Igawabfa07602015-01-20 18:47:17 +0900577 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100578 LOG.warning('router with name: %s not found for delete',
zhangguoqing6c096642016-01-04 06:17:21 +0000579 creds.router['name'])
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400580 self._clear_isolated_router(creds.router['id'],
581 creds.router['name'])
Salvatore Orlandocf996c62014-01-30 09:15:18 -0800582 if (not self.network_resources or
Salvatore Orlandocf996c62014-01-30 09:15:18 -0800583 self.network_resources.get('subnet')):
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400584 self._clear_isolated_subnet(creds.subnet['id'],
585 creds.subnet['name'])
Salvatore Orlandocf996c62014-01-30 09:15:18 -0800586 if (not self.network_resources or
587 self.network_resources.get('network')):
Andrea Frittoli (andreaf)9540dfd2015-03-25 17:06:50 -0400588 self._clear_isolated_network(creds.network['id'],
589 creds.network['name'])
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500590
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700591 def clear_creds(self):
592 if not self._creds:
Matthew Treinishb86cda92013-07-29 11:22:23 -0400593 return
Miguel Lavalleb8fabc52013-08-23 11:19:57 -0500594 self._clear_isolated_net_resources()
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600595 project_ids = set()
songwenpinge6623072021-02-22 14:47:34 +0800596 for creds in self._creds.values():
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600597 # NOTE(gmann): With new RBAC personas, we can have single project
598 # and multiple user created under it, to avoid conflict let's
599 # cleanup the projects at the end.
600 # Adding project if id is not None, means leaving domain and
601 # system creds.
602 if creds.project_id:
603 project_ids.add(creds.project_id)
Matthew Treinishb86cda92013-07-29 11:22:23 -0400604 try:
Andrea Frittolic3280152015-02-26 12:42:34 +0000605 self.creds_client.delete_user(creds.user_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900606 except lib_exc.NotFound:
Jordan Pittier525ec712016-12-07 17:51:26 +0100607 LOG.warning("user with name: %s not found for delete",
zhangguoqing6c096642016-01-04 06:17:21 +0000608 creds.username)
Colleen Murphy06374e22019-10-02 14:28:22 -0700609 # if cred is domain scoped, delete ephemeral domain
610 # do not delete default domain
611 if (hasattr(creds, 'domain_id') and
612 creds.domain_id != creds.project_domain_id):
613 try:
614 self.creds_client.delete_domain(creds.domain_id)
615 except lib_exc.NotFound:
616 LOG.warning("domain with name: %s not found for delete",
617 creds.domain_name)
Ghanshyam Mann35fc95d2023-01-18 23:22:29 -0600618 for project_id in project_ids:
619 # NOTE(zhufl): Only when neutron's security_group ext is
620 # enabled, cleanup_default_secgroup will not raise error. But
621 # here cannot use test_utils.is_extension_enabled for it will
622 # cause "circular dependency". So here just use try...except to
623 # ensure tenant deletion without big changes.
624 LOG.info("Deleting project and security group for project: %s",
625 project_id)
626
627 try:
628 if self.neutron_available:
629 self.cleanup_default_secgroup(
630 self.security_groups_admin_client, project_id)
631 except lib_exc.NotFound:
632 LOG.warning("failed to cleanup tenant %s's secgroup",
633 project_id)
634 try:
635 self.creds_client.delete_project(project_id)
636 except lib_exc.NotFound:
637 LOG.warning("tenant with id: %s not found for delete",
638 project_id)
639
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700640 self._creds = {}
Andrea Frittoli8283b4e2014-07-17 13:28:58 +0100641
642 def is_multi_user(self):
643 return True
Yair Fried76488d72014-10-21 10:13:19 +0300644
645 def is_multi_tenant(self):
646 return True
Matthew Treinish4a596932015-03-06 20:37:01 -0500647
648 def is_role_available(self, role):
649 return True