blob: 6cbaa8b38573d19182cb97916c0c1a1f19ddf7c4 [file] [log] [blame]
Andrea Frittolif4510a12017-03-07 19:17:11 +00001# Copyright 2012 OpenStack Foundation
2# Copyright 2013 IBM Corp.
3# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
Andrea Frittolif4510a12017-03-07 19:17:11 +000017import netaddr
18from oslo_log import log
Goutham Pacha Ravi37ee6772019-10-18 12:53:22 -070019from oslo_utils import uuidutils
Andrea Frittolif4510a12017-03-07 19:17:11 +000020from tempest.common import image as common_image
Andrea Frittolif4510a12017-03-07 19:17:11 +000021from tempest import config
Ken'ichi Ohmichi02d1f242017-03-12 18:56:27 -070022from tempest.lib.common.utils import data_utils
Andrea Frittolif4510a12017-03-07 19:17:11 +000023from tempest.lib.common.utils import test_utils
24from tempest.lib import exceptions as lib_exc
Roman Popelka290ef292022-02-28 10:41:04 +010025from tempest.scenario import manager
Andrea Frittolif4510a12017-03-07 19:17:11 +000026
27CONF = config.CONF
28
29LOG = log.getLogger(__name__)
30
31
Roman Popelka1118f3e2022-03-21 09:18:53 +010032class ScenarioTest(manager.NetworkScenarioTest):
Andrea Frittolif4510a12017-03-07 19:17:11 +000033 """Base class for scenario tests. Uses tempest own clients. """
34
35 credentials = ['primary']
36
37 @classmethod
38 def setup_clients(cls):
39 super(ScenarioTest, cls).setup_clients()
40 # Clients (in alphabetical order)
Vu Cong Tuandb2abab2017-06-21 20:38:39 +070041 cls.flavors_client = cls.os_primary.flavors_client
Andrea Frittolif4510a12017-03-07 19:17:11 +000042 cls.compute_floating_ips_client = (
Vu Cong Tuandb2abab2017-06-21 20:38:39 +070043 cls.os_primary.compute_floating_ips_client)
Andrea Frittolif4510a12017-03-07 19:17:11 +000044 if CONF.service_available.glance:
45 # Check if glance v1 is available to determine which client to use.
46 if CONF.image_feature_enabled.api_v1:
Vu Cong Tuandb2abab2017-06-21 20:38:39 +070047 cls.image_client = cls.os_primary.image_client
Andrea Frittolif4510a12017-03-07 19:17:11 +000048 elif CONF.image_feature_enabled.api_v2:
Vu Cong Tuandb2abab2017-06-21 20:38:39 +070049 cls.image_client = cls.os_primary.image_client_v2
Andrea Frittolif4510a12017-03-07 19:17:11 +000050 else:
51 raise lib_exc.InvalidConfiguration(
52 'Either api_v1 or api_v2 must be True in '
53 '[image-feature-enabled].')
54 # Compute image client
Vu Cong Tuandb2abab2017-06-21 20:38:39 +070055 cls.compute_images_client = cls.os_primary.compute_images_client
56 cls.keypairs_client = cls.os_primary.keypairs_client
Andrea Frittolif4510a12017-03-07 19:17:11 +000057 # Nova security groups client
58 cls.compute_security_groups_client = (
Vu Cong Tuandb2abab2017-06-21 20:38:39 +070059 cls.os_primary.compute_security_groups_client)
Andrea Frittolif4510a12017-03-07 19:17:11 +000060 cls.compute_security_group_rules_client = (
Vu Cong Tuandb2abab2017-06-21 20:38:39 +070061 cls.os_primary.compute_security_group_rules_client)
62 cls.servers_client = cls.os_primary.servers_client
63 cls.interface_client = cls.os_primary.interfaces_client
Andrea Frittolif4510a12017-03-07 19:17:11 +000064 # Neutron network client
Vu Cong Tuandb2abab2017-06-21 20:38:39 +070065 cls.networks_client = cls.os_primary.networks_client
66 cls.ports_client = cls.os_primary.ports_client
67 cls.routers_client = cls.os_primary.routers_client
68 cls.subnets_client = cls.os_primary.subnets_client
69 cls.floating_ips_client = cls.os_primary.floating_ips_client
70 cls.security_groups_client = cls.os_primary.security_groups_client
Andrea Frittolif4510a12017-03-07 19:17:11 +000071 cls.security_group_rules_client = (
Vu Cong Tuandb2abab2017-06-21 20:38:39 +070072 cls.os_primary.security_group_rules_client)
Andrea Frittolif4510a12017-03-07 19:17:11 +000073
Andrea Frittolif4510a12017-03-07 19:17:11 +000074 # ## Test functions library
75 #
76 # The create_[resource] functions only return body and discard the
77 # resp part which is not used in scenario tests
78
Andrea Frittolif4510a12017-03-07 19:17:11 +000079 def _image_create(self, name, fmt, path,
80 disk_format=None, properties=None):
81 if properties is None:
82 properties = {}
83 name = data_utils.rand_name('%s-' % name)
84 params = {
85 'name': name,
86 'container_format': fmt,
87 'disk_format': disk_format or fmt,
88 }
89 if CONF.image_feature_enabled.api_v1:
90 params['is_public'] = 'False'
91 params['properties'] = properties
92 params = {'headers': common_image.image_meta_to_headers(**params)}
93 else:
94 params['visibility'] = 'private'
95 # Additional properties are flattened out in the v2 API.
96 params.update(properties)
97 body = self.image_client.create_image(**params)
98 image = body['image'] if 'image' in body else body
99 self.addCleanup(self.image_client.delete_image, image['id'])
100 self.assertEqual("queued", image['status'])
101 with open(path, 'rb') as image_file:
102 if CONF.image_feature_enabled.api_v1:
103 self.image_client.update_image(image['id'], data=image_file)
104 else:
105 self.image_client.store_image_file(image['id'], image_file)
106 return image['id']
107
108 def glance_image_create(self):
Martin Kopec258cc6c2020-04-15 22:55:25 +0000109 img_path = CONF.scenario.img_file
Andrea Frittolif4510a12017-03-07 19:17:11 +0000110 img_container_format = CONF.scenario.img_container_format
111 img_disk_format = CONF.scenario.img_disk_format
112 img_properties = CONF.scenario.img_properties
113 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Martin Kopec258cc6c2020-04-15 22:55:25 +0000114 "properties: %s",
Andrea Frittolif4510a12017-03-07 19:17:11 +0000115 img_path, img_container_format, img_disk_format,
Martin Kopec258cc6c2020-04-15 22:55:25 +0000116 img_properties)
117 image = self._image_create('scenario-img',
118 img_container_format,
119 img_path,
120 disk_format=img_disk_format,
121 properties=img_properties)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000122 LOG.debug("image:%s", image)
123
124 return image
125
Andrea Frittolif4510a12017-03-07 19:17:11 +0000126 def _log_net_info(self, exc):
127 # network debug is called as part of ssh init
128 if not isinstance(exc, lib_exc.SSHTimeout):
129 LOG.debug('Network information on a devstack host')
130
Andrea Frittolif4510a12017-03-07 19:17:11 +0000131
132class NetworkScenarioTest(ScenarioTest):
133 """Base class for network scenario tests.
134
135 This class provide helpers for network scenario tests, using the neutron
136 API. Helpers from ancestor which use the nova network API are overridden
137 with the neutron API.
138
139 This Class also enforces using Neutron instead of novanetwork.
140 Subclassed tests will be skipped if Neutron is not enabled
141
142 """
143
144 credentials = ['primary', 'admin']
145
146 @classmethod
147 def skip_checks(cls):
148 super(NetworkScenarioTest, cls).skip_checks()
149 if not CONF.service_available.neutron:
150 raise cls.skipException('Neutron not available')
151
Andrea Frittolif4510a12017-03-07 19:17:11 +0000152 def _create_subnet(self, network, subnets_client=None,
153 routers_client=None, namestart='subnet-smoke',
154 **kwargs):
155 """Create a subnet for the given network
156
157 within the cidr block configured for tenant networks.
158 """
159 if not subnets_client:
160 subnets_client = self.subnets_client
161 if not routers_client:
162 routers_client = self.routers_client
163
164 def cidr_in_use(cidr, tenant_id):
165 """Check cidr existence
166
167 :returns: True if subnet with cidr already exist in tenant
168 False else
169 """
Vu Cong Tuan99751862017-06-23 19:46:40 +0700170 cidr_in_use = self.os_admin.subnets_client.list_subnets(
Andrea Frittolif4510a12017-03-07 19:17:11 +0000171 tenant_id=tenant_id, cidr=cidr)['subnets']
172 return len(cidr_in_use) != 0
173
Rodrigo Barbieri797257e2017-11-21 11:00:45 -0200174 def _make_create_subnet_request(namestart, network,
175 ip_version, subnets_client, **kwargs):
Andrea Frittolif4510a12017-03-07 19:17:11 +0000176
177 subnet = dict(
178 name=data_utils.rand_name(namestart),
179 network_id=network['id'],
180 tenant_id=network['tenant_id'],
Andrea Frittolif4510a12017-03-07 19:17:11 +0000181 ip_version=ip_version,
182 **kwargs
183 )
Rodrigo Barbieri797257e2017-11-21 11:00:45 -0200184
185 if ip_version == 6:
186 subnet['ipv6_address_mode'] = 'slaac'
187 subnet['ipv6_ra_mode'] = 'slaac'
188
Andrea Frittolif4510a12017-03-07 19:17:11 +0000189 try:
Rodrigo Barbieri797257e2017-11-21 11:00:45 -0200190 return subnets_client.create_subnet(**subnet)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000191 except lib_exc.Conflict as e:
haixin48895812020-09-30 13:50:37 +0800192 if 'overlaps with another subnet' not in str(e):
Andrea Frittolif4510a12017-03-07 19:17:11 +0000193 raise
Rodrigo Barbieri797257e2017-11-21 11:00:45 -0200194
195 result = None
196 str_cidr = None
197
198 use_default_subnetpool = kwargs.get('use_default_subnetpool', False)
199
200 ip_version = kwargs.pop('ip_version', 4)
201
202 if not use_default_subnetpool:
203
204 if ip_version == 6:
205 tenant_cidr = netaddr.IPNetwork(
206 CONF.network.project_network_v6_cidr)
207 num_bits = CONF.network.project_network_v6_mask_bits
208 else:
209 tenant_cidr = netaddr.IPNetwork(
210 CONF.network.project_network_cidr)
211 num_bits = CONF.network.project_network_mask_bits
212
213 # Repeatedly attempt subnet creation with sequential cidr
214 # blocks until an unallocated block is found.
215 for subnet_cidr in tenant_cidr.subnet(num_bits):
216 str_cidr = str(subnet_cidr)
217 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
218 continue
219
220 result = _make_create_subnet_request(
221 namestart, network, ip_version, subnets_client,
222 cidr=str_cidr, **kwargs)
223 if result is not None:
224 break
225 else:
226 result = _make_create_subnet_request(
227 namestart, network, ip_version, subnets_client,
228 **kwargs)
229
230 self.assertIsNotNone(result)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000231
232 subnet = result['subnet']
Rodrigo Barbieri797257e2017-11-21 11:00:45 -0200233 if str_cidr is not None:
234 self.assertEqual(subnet['cidr'], str_cidr)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000235
236 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
237 subnets_client.delete_subnet, subnet['id'])
238
239 return subnet
240
Goutham Pacha Ravi37ee6772019-10-18 12:53:22 -0700241 def _get_network_by_name_or_id(self, identifier):
242
243 if uuidutils.is_uuid_like(identifier):
244 return self.os_admin.networks_client.show_network(
245 identifier)['network']
246
247 networks = self.os_admin.networks_client.list_networks(
248 name=identifier)['networks']
249 self.assertNotEqual(len(networks), 0,
250 "Unable to get network by name: %s" % identifier)
251 return networks[0]
252
253 def get_networks(self):
254 return self.os_admin.networks_client.list_networks()['networks']
Andrea Frittolif4510a12017-03-07 19:17:11 +0000255
256 def create_floating_ip(self, thing, external_network_id=None,
lkuchlan7636a1f2020-04-30 16:13:13 +0300257 port_id=None, ip_addr=None, client=None):
Andrea Frittolif4510a12017-03-07 19:17:11 +0000258 """Create a floating IP and associates to a resource/port on Neutron"""
259 if not external_network_id:
260 external_network_id = CONF.network.public_network_id
261 if not client:
262 client = self.floating_ips_client
263 if not port_id:
Roman Popelkaf880ce32022-03-22 13:26:51 +0100264 port_id, ip4 = self.get_server_port_id_and_ip4(thing,
265 ip_addr=ip_addr)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000266 else:
267 ip4 = None
268 result = client.create_floatingip(
269 floating_network_id=external_network_id,
270 port_id=port_id,
271 tenant_id=thing['tenant_id'],
272 fixed_ip_address=ip4
273 )
274 floating_ip = result['floatingip']
275 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
276 client.delete_floatingip,
277 floating_ip['id'])
278 return floating_ip
279
Andrea Frittolif4510a12017-03-07 19:17:11 +0000280 def _check_tenant_network_connectivity(self, server,
281 username,
282 private_key,
283 should_connect=True,
284 servers_for_debug=None):
285 if not CONF.network.project_networks_reachable:
286 msg = 'Tenant networks not configured to be reachable.'
287 LOG.info(msg)
288 return
289 # The target login is assumed to have been configured for
290 # key-based authentication by cloud-init.
291 try:
292 for ip_addresses in server['addresses'].values():
293 for ip_address in ip_addresses:
294 self.check_vm_connectivity(ip_address['addr'],
295 username,
296 private_key,
Roman Popelkafd4e2f32022-03-21 10:16:30 +0100297 should_connect=should_connect,
298 server=server)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000299 except Exception as e:
300 LOG.exception('Tenant network connectivity check failed')
Roman Popelka164898c2022-03-21 09:12:38 +0100301 self.log_console_output(servers_for_debug)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000302 self._log_net_info(e)
303 raise
304
305 def _check_remote_connectivity(self, source, dest, should_succeed=True,
306 nic=None):
307 """assert ping server via source ssh connection
308
309 Note: This is an internal method. Use check_remote_connectivity
310 instead.
311
312 :param source: RemoteClient: an ssh connection from which to ping
313 :param dest: and IP to ping against
314 :param should_succeed: boolean should ping succeed or not
315 :param nic: specific network interface to ping from
316 """
317 def ping_remote():
318 try:
319 source.ping_host(dest, nic=nic)
320 except lib_exc.SSHExecCommandFailed:
321 LOG.warning('Failed to ping IP: %s via a ssh connection '
322 'from: %s.', dest, source.ssh_client.host)
323 return not should_succeed
324 return should_succeed
325
326 return test_utils.call_until_true(ping_remote,
327 CONF.validation.ping_timeout,
328 1)
329
330 def check_remote_connectivity(self, source, dest, should_succeed=True,
331 nic=None):
332 """assert ping server via source ssh connection
333
334 :param source: RemoteClient: an ssh connection from which to ping
335 :param dest: and IP to ping against
336 :param should_succeed: boolean should ping succeed or not
337 :param nic: specific network interface to ping from
338 """
339 result = self._check_remote_connectivity(source, dest, should_succeed,
340 nic)
341 source_host = source.ssh_client.host
342 if should_succeed:
zhongjun39e9c582017-06-21 15:17:11 +0800343 msg = ("Timed out waiting for %s to become reachable from %s"
344 % (dest, source_host))
Andrea Frittolif4510a12017-03-07 19:17:11 +0000345 else:
346 msg = "%s is reachable from %s" % (dest, source_host)
347 self.assertTrue(result, msg)
348
349 def _create_security_group(self, security_group_rules_client=None,
350 tenant_id=None,
351 namestart='secgroup-smoke',
352 security_groups_client=None):
353 if security_group_rules_client is None:
354 security_group_rules_client = self.security_group_rules_client
355 if security_groups_client is None:
356 security_groups_client = self.security_groups_client
357 if tenant_id is None:
358 tenant_id = security_groups_client.tenant_id
359 secgroup = self._create_empty_security_group(
360 namestart=namestart, client=security_groups_client,
361 tenant_id=tenant_id)
362
363 # Add rules to the security group
364 rules = self._create_loginable_secgroup_rule(
365 security_group_rules_client=security_group_rules_client,
366 secgroup=secgroup,
367 security_groups_client=security_groups_client)
368 for rule in rules:
369 self.assertEqual(tenant_id, rule['tenant_id'])
370 self.assertEqual(secgroup['id'], rule['security_group_id'])
371 return secgroup
372
373 def _create_empty_security_group(self, client=None, tenant_id=None,
374 namestart='secgroup-smoke'):
375 """Create a security group without rules.
376
377 Default rules will be created:
378 - IPv4 egress to any
379 - IPv6 egress to any
380
381 :param tenant_id: secgroup will be created in this tenant
382 :returns: the created security group
383 """
384 if client is None:
385 client = self.security_groups_client
386 if not tenant_id:
387 tenant_id = client.tenant_id
388 sg_name = data_utils.rand_name(namestart)
389 sg_desc = sg_name + " description"
390 sg_dict = dict(name=sg_name,
391 description=sg_desc)
392 sg_dict['tenant_id'] = tenant_id
393 result = client.create_security_group(**sg_dict)
394
395 secgroup = result['security_group']
396 self.assertEqual(secgroup['name'], sg_name)
397 self.assertEqual(tenant_id, secgroup['tenant_id'])
398 self.assertEqual(secgroup['description'], sg_desc)
399
400 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
401 client.delete_security_group, secgroup['id'])
402 return secgroup
403
404 def _default_security_group(self, client=None, tenant_id=None):
405 """Get default secgroup for given tenant_id.
406
407 :returns: default secgroup for given tenant
408 """
409 if client is None:
410 client = self.security_groups_client
411 if not tenant_id:
412 tenant_id = client.tenant_id
413 sgs = [
414 sg for sg in list(client.list_security_groups().values())[0]
415 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
416 ]
417 msg = "No default security group for tenant %s." % (tenant_id)
418 self.assertGreater(len(sgs), 0, msg)
419 return sgs[0]
420
421 def _create_security_group_rule(self, secgroup=None,
422 sec_group_rules_client=None,
423 tenant_id=None,
424 security_groups_client=None, **kwargs):
425 """Create a rule from a dictionary of rule parameters.
426
427 Create a rule in a secgroup. if secgroup not defined will search for
428 default secgroup in tenant_id.
429
430 :param secgroup: the security group.
431 :param tenant_id: if secgroup not passed -- the tenant in which to
432 search for default secgroup
433 :param kwargs: a dictionary containing rule parameters:
434 for example, to allow incoming ssh:
435 rule = {
436 direction: 'ingress'
437 protocol:'tcp',
438 port_range_min: 22,
439 port_range_max: 22
440 }
441 """
442 if sec_group_rules_client is None:
443 sec_group_rules_client = self.security_group_rules_client
444 if security_groups_client is None:
445 security_groups_client = self.security_groups_client
446 if not tenant_id:
447 tenant_id = security_groups_client.tenant_id
448 if secgroup is None:
449 secgroup = self._default_security_group(
450 client=security_groups_client, tenant_id=tenant_id)
451
452 ruleset = dict(security_group_id=secgroup['id'],
453 tenant_id=secgroup['tenant_id'])
454 ruleset.update(kwargs)
455
456 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
457 sg_rule = sg_rule['security_group_rule']
458
459 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
460 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
461
462 return sg_rule
463
464 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
465 secgroup=None,
466 security_groups_client=None):
467 """Create loginable security group rule
468
469 This function will create:
470 1. egress and ingress tcp port 22 allow rule in order to allow ssh
471 access for ipv4.
472 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
473 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
474 """
475
476 if security_group_rules_client is None:
477 security_group_rules_client = self.security_group_rules_client
478 if security_groups_client is None:
479 security_groups_client = self.security_groups_client
480 rules = []
481 rulesets = [
482 dict(
483 # ssh
484 protocol='tcp',
485 port_range_min=22,
486 port_range_max=22,
487 ),
488 dict(
Rodrigo Barbieri797257e2017-11-21 11:00:45 -0200489 # ipv6-ssh
490 protocol='tcp',
491 port_range_min=22,
492 port_range_max=22,
493 ethertype='IPv6',
494 ),
495 dict(
Andrea Frittolif4510a12017-03-07 19:17:11 +0000496 # ping
497 protocol='icmp',
498 ),
499 dict(
500 # ipv6-icmp for ping6
501 protocol='icmp',
502 ethertype='IPv6',
503 )
504 ]
505 sec_group_rules_client = security_group_rules_client
506 for ruleset in rulesets:
507 for r_direction in ['ingress', 'egress']:
508 ruleset['direction'] = r_direction
509 try:
510 sg_rule = self._create_security_group_rule(
511 sec_group_rules_client=sec_group_rules_client,
512 secgroup=secgroup,
513 security_groups_client=security_groups_client,
514 **ruleset)
515 except lib_exc.Conflict as ex:
516 # if rule already exist - skip rule and continue
517 msg = 'Security group rule already exists'
518 if msg not in ex._error_string:
519 raise ex
520 else:
521 self.assertEqual(r_direction, sg_rule['direction'])
522 rules.append(sg_rule)
523
524 return rules
525
526 def _get_router(self, client=None, tenant_id=None):
527 """Retrieve a router for the given tenant id.
528
529 If a public router has been configured, it will be returned.
530
531 If a public router has not been configured, but a public
532 network has, a tenant router will be created and returned that
533 routes traffic to the public network.
534 """
535 if not client:
536 client = self.routers_client
537 if not tenant_id:
538 tenant_id = client.tenant_id
539 router_id = CONF.network.public_router_id
540 network_id = CONF.network.public_network_id
541 if router_id:
542 body = client.show_router(router_id)
543 return body['router']
544 elif network_id:
545 router = self._create_router(client, tenant_id)
546 kwargs = {'external_gateway_info': dict(network_id=network_id)}
547 router = client.update_router(router['id'], **kwargs)['router']
548 return router
549 else:
550 raise Exception("Neither of 'public_router_id' or "
551 "'public_network_id' has been defined.")
552
553 def _create_router(self, client=None, tenant_id=None,
554 namestart='router-smoke'):
555 if not client:
556 client = self.routers_client
557 if not tenant_id:
558 tenant_id = client.tenant_id
559 name = data_utils.rand_name(namestart)
560 result = client.create_router(name=name,
561 admin_state_up=True,
562 tenant_id=tenant_id)
563 router = result['router']
564 self.assertEqual(router['name'], name)
565 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
566 client.delete_router,
567 router['id'])
568 return router
569
570 def _update_router_admin_state(self, router, admin_state_up):
571 kwargs = dict(admin_state_up=admin_state_up)
572 router = self.routers_client.update_router(
573 router['id'], **kwargs)['router']
574 self.assertEqual(admin_state_up, router['admin_state_up'])
575
576 def create_networks(self, networks_client=None,
577 routers_client=None, subnets_client=None,
578 tenant_id=None, dns_nameservers=None,
579 port_security_enabled=True):
580 """Create a network with a subnet connected to a router.
581
582 The baremetal driver is a special case since all nodes are
583 on the same shared network.
584
585 :param tenant_id: id of tenant to create resources in.
586 :param dns_nameservers: list of dns servers to send to subnet.
587 :returns: network, subnet, router
588 """
589 if CONF.network.shared_physical_network:
590 # NOTE(Shrews): This exception is for environments where tenant
591 # credential isolation is available, but network separation is
592 # not (the current baremetal case). Likely can be removed when
593 # test account mgmt is reworked:
594 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
595 if not CONF.compute.fixed_network_name:
596 m = 'fixed_network_name must be specified in config'
597 raise lib_exc.InvalidConfiguration(m)
Goutham Pacha Ravi37ee6772019-10-18 12:53:22 -0700598 network = self._get_network_by_name_or_id(
Andrea Frittolif4510a12017-03-07 19:17:11 +0000599 CONF.compute.fixed_network_name)
600 router = None
601 subnet = None
602 else:
Roman Popelka1118f3e2022-03-21 09:18:53 +0100603 network = self.create_network(
Andrea Frittolif4510a12017-03-07 19:17:11 +0000604 networks_client=networks_client,
605 tenant_id=tenant_id,
606 port_security_enabled=port_security_enabled)
607 router = self._get_router(client=routers_client,
608 tenant_id=tenant_id)
609 subnet_kwargs = dict(network=network,
610 subnets_client=subnets_client,
611 routers_client=routers_client)
612 # use explicit check because empty list is a valid option
613 if dns_nameservers is not None:
614 subnet_kwargs['dns_nameservers'] = dns_nameservers
615 subnet = self._create_subnet(**subnet_kwargs)
616 if not routers_client:
617 routers_client = self.routers_client
618 router_id = router['id']
619 routers_client.add_router_interface(router_id,
620 subnet_id=subnet['id'])
621
622 # save a cleanup job to remove this association between
623 # router and subnet
624 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
625 routers_client.remove_router_interface, router_id,
626 subnet_id=subnet['id'])
627 return network, subnet, router