blob: d47d1b353c3008fe081ba2eee0a293a73b3b29cc [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 _create_loginable_secgroup_rule(self, secgroup_id=None):
80 _client = self.compute_security_groups_client
81 _client_rules = self.compute_security_group_rules_client
82 if secgroup_id is None:
83 sgs = _client.list_security_groups()['security_groups']
84 for sg in sgs:
85 if sg['name'] == 'default':
86 secgroup_id = sg['id']
87
88 # These rules are intended to permit inbound ssh and icmp
89 # traffic from all sources, so no group_id is provided.
90 # Setting a group_id would only permit traffic from ports
91 # belonging to the same security group.
92 rulesets = [
93 {
94 # ssh
95 'ip_protocol': 'tcp',
96 'from_port': 22,
97 'to_port': 22,
98 'cidr': '0.0.0.0/0',
99 },
100 {
101 # ping
102 'ip_protocol': 'icmp',
103 'from_port': -1,
104 'to_port': -1,
105 'cidr': '0.0.0.0/0',
106 }
107 ]
108 rules = list()
109 for ruleset in rulesets:
110 sg_rule = _client_rules.create_security_group_rule(
111 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
112 rules.append(sg_rule)
113 return rules
114
115 def _create_security_group(self):
116 # Create security group
117 sg_name = data_utils.rand_name(self.__class__.__name__)
118 sg_desc = sg_name + " description"
119 secgroup = self.compute_security_groups_client.create_security_group(
120 name=sg_name, description=sg_desc)['security_group']
121 self.assertEqual(secgroup['name'], sg_name)
122 self.assertEqual(secgroup['description'], sg_desc)
123 self.addCleanup(
124 test_utils.call_and_ignore_notfound_exc,
125 self.compute_security_groups_client.delete_security_group,
126 secgroup['id'])
127
128 # Add rules to the security group
129 self._create_loginable_secgroup_rule(secgroup['id'])
130
131 return secgroup
132
Andrea Frittolif4510a12017-03-07 19:17:11 +0000133 def _image_create(self, name, fmt, path,
134 disk_format=None, properties=None):
135 if properties is None:
136 properties = {}
137 name = data_utils.rand_name('%s-' % name)
138 params = {
139 'name': name,
140 'container_format': fmt,
141 'disk_format': disk_format or fmt,
142 }
143 if CONF.image_feature_enabled.api_v1:
144 params['is_public'] = 'False'
145 params['properties'] = properties
146 params = {'headers': common_image.image_meta_to_headers(**params)}
147 else:
148 params['visibility'] = 'private'
149 # Additional properties are flattened out in the v2 API.
150 params.update(properties)
151 body = self.image_client.create_image(**params)
152 image = body['image'] if 'image' in body else body
153 self.addCleanup(self.image_client.delete_image, image['id'])
154 self.assertEqual("queued", image['status'])
155 with open(path, 'rb') as image_file:
156 if CONF.image_feature_enabled.api_v1:
157 self.image_client.update_image(image['id'], data=image_file)
158 else:
159 self.image_client.store_image_file(image['id'], image_file)
160 return image['id']
161
162 def glance_image_create(self):
Martin Kopec258cc6c2020-04-15 22:55:25 +0000163 img_path = CONF.scenario.img_file
Andrea Frittolif4510a12017-03-07 19:17:11 +0000164 img_container_format = CONF.scenario.img_container_format
165 img_disk_format = CONF.scenario.img_disk_format
166 img_properties = CONF.scenario.img_properties
167 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Martin Kopec258cc6c2020-04-15 22:55:25 +0000168 "properties: %s",
Andrea Frittolif4510a12017-03-07 19:17:11 +0000169 img_path, img_container_format, img_disk_format,
Martin Kopec258cc6c2020-04-15 22:55:25 +0000170 img_properties)
171 image = self._image_create('scenario-img',
172 img_container_format,
173 img_path,
174 disk_format=img_disk_format,
175 properties=img_properties)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000176 LOG.debug("image:%s", image)
177
178 return image
179
Andrea Frittolif4510a12017-03-07 19:17:11 +0000180 def _log_net_info(self, exc):
181 # network debug is called as part of ssh init
182 if not isinstance(exc, lib_exc.SSHTimeout):
183 LOG.debug('Network information on a devstack host')
184
Andrea Frittolif4510a12017-03-07 19:17:11 +0000185
186class NetworkScenarioTest(ScenarioTest):
187 """Base class for network scenario tests.
188
189 This class provide helpers for network scenario tests, using the neutron
190 API. Helpers from ancestor which use the nova network API are overridden
191 with the neutron API.
192
193 This Class also enforces using Neutron instead of novanetwork.
194 Subclassed tests will be skipped if Neutron is not enabled
195
196 """
197
198 credentials = ['primary', 'admin']
199
200 @classmethod
201 def skip_checks(cls):
202 super(NetworkScenarioTest, cls).skip_checks()
203 if not CONF.service_available.neutron:
204 raise cls.skipException('Neutron not available')
205
Andrea Frittolif4510a12017-03-07 19:17:11 +0000206 def _create_subnet(self, network, subnets_client=None,
207 routers_client=None, namestart='subnet-smoke',
208 **kwargs):
209 """Create a subnet for the given network
210
211 within the cidr block configured for tenant networks.
212 """
213 if not subnets_client:
214 subnets_client = self.subnets_client
215 if not routers_client:
216 routers_client = self.routers_client
217
218 def cidr_in_use(cidr, tenant_id):
219 """Check cidr existence
220
221 :returns: True if subnet with cidr already exist in tenant
222 False else
223 """
Vu Cong Tuan99751862017-06-23 19:46:40 +0700224 cidr_in_use = self.os_admin.subnets_client.list_subnets(
Andrea Frittolif4510a12017-03-07 19:17:11 +0000225 tenant_id=tenant_id, cidr=cidr)['subnets']
226 return len(cidr_in_use) != 0
227
Rodrigo Barbieri797257e2017-11-21 11:00:45 -0200228 def _make_create_subnet_request(namestart, network,
229 ip_version, subnets_client, **kwargs):
Andrea Frittolif4510a12017-03-07 19:17:11 +0000230
231 subnet = dict(
232 name=data_utils.rand_name(namestart),
233 network_id=network['id'],
234 tenant_id=network['tenant_id'],
Andrea Frittolif4510a12017-03-07 19:17:11 +0000235 ip_version=ip_version,
236 **kwargs
237 )
Rodrigo Barbieri797257e2017-11-21 11:00:45 -0200238
239 if ip_version == 6:
240 subnet['ipv6_address_mode'] = 'slaac'
241 subnet['ipv6_ra_mode'] = 'slaac'
242
Andrea Frittolif4510a12017-03-07 19:17:11 +0000243 try:
Rodrigo Barbieri797257e2017-11-21 11:00:45 -0200244 return subnets_client.create_subnet(**subnet)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000245 except lib_exc.Conflict as e:
haixin48895812020-09-30 13:50:37 +0800246 if 'overlaps with another subnet' not in str(e):
Andrea Frittolif4510a12017-03-07 19:17:11 +0000247 raise
Rodrigo Barbieri797257e2017-11-21 11:00:45 -0200248
249 result = None
250 str_cidr = None
251
252 use_default_subnetpool = kwargs.get('use_default_subnetpool', False)
253
254 ip_version = kwargs.pop('ip_version', 4)
255
256 if not use_default_subnetpool:
257
258 if ip_version == 6:
259 tenant_cidr = netaddr.IPNetwork(
260 CONF.network.project_network_v6_cidr)
261 num_bits = CONF.network.project_network_v6_mask_bits
262 else:
263 tenant_cidr = netaddr.IPNetwork(
264 CONF.network.project_network_cidr)
265 num_bits = CONF.network.project_network_mask_bits
266
267 # Repeatedly attempt subnet creation with sequential cidr
268 # blocks until an unallocated block is found.
269 for subnet_cidr in tenant_cidr.subnet(num_bits):
270 str_cidr = str(subnet_cidr)
271 if cidr_in_use(str_cidr, tenant_id=network['tenant_id']):
272 continue
273
274 result = _make_create_subnet_request(
275 namestart, network, ip_version, subnets_client,
276 cidr=str_cidr, **kwargs)
277 if result is not None:
278 break
279 else:
280 result = _make_create_subnet_request(
281 namestart, network, ip_version, subnets_client,
282 **kwargs)
283
284 self.assertIsNotNone(result)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000285
286 subnet = result['subnet']
Rodrigo Barbieri797257e2017-11-21 11:00:45 -0200287 if str_cidr is not None:
288 self.assertEqual(subnet['cidr'], str_cidr)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000289
290 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
291 subnets_client.delete_subnet, subnet['id'])
292
293 return subnet
294
Goutham Pacha Ravi37ee6772019-10-18 12:53:22 -0700295 def _get_network_by_name_or_id(self, identifier):
296
297 if uuidutils.is_uuid_like(identifier):
298 return self.os_admin.networks_client.show_network(
299 identifier)['network']
300
301 networks = self.os_admin.networks_client.list_networks(
302 name=identifier)['networks']
303 self.assertNotEqual(len(networks), 0,
304 "Unable to get network by name: %s" % identifier)
305 return networks[0]
306
307 def get_networks(self):
308 return self.os_admin.networks_client.list_networks()['networks']
Andrea Frittolif4510a12017-03-07 19:17:11 +0000309
310 def create_floating_ip(self, thing, external_network_id=None,
lkuchlan7636a1f2020-04-30 16:13:13 +0300311 port_id=None, ip_addr=None, client=None):
Andrea Frittolif4510a12017-03-07 19:17:11 +0000312 """Create a floating IP and associates to a resource/port on Neutron"""
313 if not external_network_id:
314 external_network_id = CONF.network.public_network_id
315 if not client:
316 client = self.floating_ips_client
317 if not port_id:
Roman Popelkaf880ce32022-03-22 13:26:51 +0100318 port_id, ip4 = self.get_server_port_id_and_ip4(thing,
319 ip_addr=ip_addr)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000320 else:
321 ip4 = None
322 result = client.create_floatingip(
323 floating_network_id=external_network_id,
324 port_id=port_id,
325 tenant_id=thing['tenant_id'],
326 fixed_ip_address=ip4
327 )
328 floating_ip = result['floatingip']
329 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
330 client.delete_floatingip,
331 floating_ip['id'])
332 return floating_ip
333
Andrea Frittolif4510a12017-03-07 19:17:11 +0000334 def _check_tenant_network_connectivity(self, server,
335 username,
336 private_key,
337 should_connect=True,
338 servers_for_debug=None):
339 if not CONF.network.project_networks_reachable:
340 msg = 'Tenant networks not configured to be reachable.'
341 LOG.info(msg)
342 return
343 # The target login is assumed to have been configured for
344 # key-based authentication by cloud-init.
345 try:
346 for ip_addresses in server['addresses'].values():
347 for ip_address in ip_addresses:
348 self.check_vm_connectivity(ip_address['addr'],
349 username,
350 private_key,
Roman Popelkafd4e2f32022-03-21 10:16:30 +0100351 should_connect=should_connect,
352 server=server)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000353 except Exception as e:
354 LOG.exception('Tenant network connectivity check failed')
Roman Popelka164898c2022-03-21 09:12:38 +0100355 self.log_console_output(servers_for_debug)
Andrea Frittolif4510a12017-03-07 19:17:11 +0000356 self._log_net_info(e)
357 raise
358
359 def _check_remote_connectivity(self, source, dest, should_succeed=True,
360 nic=None):
361 """assert ping server via source ssh connection
362
363 Note: This is an internal method. Use check_remote_connectivity
364 instead.
365
366 :param source: RemoteClient: an ssh connection from which to ping
367 :param dest: and IP to ping against
368 :param should_succeed: boolean should ping succeed or not
369 :param nic: specific network interface to ping from
370 """
371 def ping_remote():
372 try:
373 source.ping_host(dest, nic=nic)
374 except lib_exc.SSHExecCommandFailed:
375 LOG.warning('Failed to ping IP: %s via a ssh connection '
376 'from: %s.', dest, source.ssh_client.host)
377 return not should_succeed
378 return should_succeed
379
380 return test_utils.call_until_true(ping_remote,
381 CONF.validation.ping_timeout,
382 1)
383
384 def check_remote_connectivity(self, source, dest, should_succeed=True,
385 nic=None):
386 """assert ping server via source ssh connection
387
388 :param source: RemoteClient: an ssh connection from which to ping
389 :param dest: and IP to ping against
390 :param should_succeed: boolean should ping succeed or not
391 :param nic: specific network interface to ping from
392 """
393 result = self._check_remote_connectivity(source, dest, should_succeed,
394 nic)
395 source_host = source.ssh_client.host
396 if should_succeed:
zhongjun39e9c582017-06-21 15:17:11 +0800397 msg = ("Timed out waiting for %s to become reachable from %s"
398 % (dest, source_host))
Andrea Frittolif4510a12017-03-07 19:17:11 +0000399 else:
400 msg = "%s is reachable from %s" % (dest, source_host)
401 self.assertTrue(result, msg)
402
403 def _create_security_group(self, security_group_rules_client=None,
404 tenant_id=None,
405 namestart='secgroup-smoke',
406 security_groups_client=None):
407 if security_group_rules_client is None:
408 security_group_rules_client = self.security_group_rules_client
409 if security_groups_client is None:
410 security_groups_client = self.security_groups_client
411 if tenant_id is None:
412 tenant_id = security_groups_client.tenant_id
413 secgroup = self._create_empty_security_group(
414 namestart=namestart, client=security_groups_client,
415 tenant_id=tenant_id)
416
417 # Add rules to the security group
418 rules = self._create_loginable_secgroup_rule(
419 security_group_rules_client=security_group_rules_client,
420 secgroup=secgroup,
421 security_groups_client=security_groups_client)
422 for rule in rules:
423 self.assertEqual(tenant_id, rule['tenant_id'])
424 self.assertEqual(secgroup['id'], rule['security_group_id'])
425 return secgroup
426
427 def _create_empty_security_group(self, client=None, tenant_id=None,
428 namestart='secgroup-smoke'):
429 """Create a security group without rules.
430
431 Default rules will be created:
432 - IPv4 egress to any
433 - IPv6 egress to any
434
435 :param tenant_id: secgroup will be created in this tenant
436 :returns: the created security group
437 """
438 if client is None:
439 client = self.security_groups_client
440 if not tenant_id:
441 tenant_id = client.tenant_id
442 sg_name = data_utils.rand_name(namestart)
443 sg_desc = sg_name + " description"
444 sg_dict = dict(name=sg_name,
445 description=sg_desc)
446 sg_dict['tenant_id'] = tenant_id
447 result = client.create_security_group(**sg_dict)
448
449 secgroup = result['security_group']
450 self.assertEqual(secgroup['name'], sg_name)
451 self.assertEqual(tenant_id, secgroup['tenant_id'])
452 self.assertEqual(secgroup['description'], sg_desc)
453
454 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
455 client.delete_security_group, secgroup['id'])
456 return secgroup
457
458 def _default_security_group(self, client=None, tenant_id=None):
459 """Get default secgroup for given tenant_id.
460
461 :returns: default secgroup for given tenant
462 """
463 if client is None:
464 client = self.security_groups_client
465 if not tenant_id:
466 tenant_id = client.tenant_id
467 sgs = [
468 sg for sg in list(client.list_security_groups().values())[0]
469 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
470 ]
471 msg = "No default security group for tenant %s." % (tenant_id)
472 self.assertGreater(len(sgs), 0, msg)
473 return sgs[0]
474
475 def _create_security_group_rule(self, secgroup=None,
476 sec_group_rules_client=None,
477 tenant_id=None,
478 security_groups_client=None, **kwargs):
479 """Create a rule from a dictionary of rule parameters.
480
481 Create a rule in a secgroup. if secgroup not defined will search for
482 default secgroup in tenant_id.
483
484 :param secgroup: the security group.
485 :param tenant_id: if secgroup not passed -- the tenant in which to
486 search for default secgroup
487 :param kwargs: a dictionary containing rule parameters:
488 for example, to allow incoming ssh:
489 rule = {
490 direction: 'ingress'
491 protocol:'tcp',
492 port_range_min: 22,
493 port_range_max: 22
494 }
495 """
496 if sec_group_rules_client is None:
497 sec_group_rules_client = self.security_group_rules_client
498 if security_groups_client is None:
499 security_groups_client = self.security_groups_client
500 if not tenant_id:
501 tenant_id = security_groups_client.tenant_id
502 if secgroup is None:
503 secgroup = self._default_security_group(
504 client=security_groups_client, tenant_id=tenant_id)
505
506 ruleset = dict(security_group_id=secgroup['id'],
507 tenant_id=secgroup['tenant_id'])
508 ruleset.update(kwargs)
509
510 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
511 sg_rule = sg_rule['security_group_rule']
512
513 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
514 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
515
516 return sg_rule
517
518 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
519 secgroup=None,
520 security_groups_client=None):
521 """Create loginable security group rule
522
523 This function will create:
524 1. egress and ingress tcp port 22 allow rule in order to allow ssh
525 access for ipv4.
526 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
527 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
528 """
529
530 if security_group_rules_client is None:
531 security_group_rules_client = self.security_group_rules_client
532 if security_groups_client is None:
533 security_groups_client = self.security_groups_client
534 rules = []
535 rulesets = [
536 dict(
537 # ssh
538 protocol='tcp',
539 port_range_min=22,
540 port_range_max=22,
541 ),
542 dict(
Rodrigo Barbieri797257e2017-11-21 11:00:45 -0200543 # ipv6-ssh
544 protocol='tcp',
545 port_range_min=22,
546 port_range_max=22,
547 ethertype='IPv6',
548 ),
549 dict(
Andrea Frittolif4510a12017-03-07 19:17:11 +0000550 # ping
551 protocol='icmp',
552 ),
553 dict(
554 # ipv6-icmp for ping6
555 protocol='icmp',
556 ethertype='IPv6',
557 )
558 ]
559 sec_group_rules_client = security_group_rules_client
560 for ruleset in rulesets:
561 for r_direction in ['ingress', 'egress']:
562 ruleset['direction'] = r_direction
563 try:
564 sg_rule = self._create_security_group_rule(
565 sec_group_rules_client=sec_group_rules_client,
566 secgroup=secgroup,
567 security_groups_client=security_groups_client,
568 **ruleset)
569 except lib_exc.Conflict as ex:
570 # if rule already exist - skip rule and continue
571 msg = 'Security group rule already exists'
572 if msg not in ex._error_string:
573 raise ex
574 else:
575 self.assertEqual(r_direction, sg_rule['direction'])
576 rules.append(sg_rule)
577
578 return rules
579
580 def _get_router(self, client=None, tenant_id=None):
581 """Retrieve a router for the given tenant id.
582
583 If a public router has been configured, it will be returned.
584
585 If a public router has not been configured, but a public
586 network has, a tenant router will be created and returned that
587 routes traffic to the public network.
588 """
589 if not client:
590 client = self.routers_client
591 if not tenant_id:
592 tenant_id = client.tenant_id
593 router_id = CONF.network.public_router_id
594 network_id = CONF.network.public_network_id
595 if router_id:
596 body = client.show_router(router_id)
597 return body['router']
598 elif network_id:
599 router = self._create_router(client, tenant_id)
600 kwargs = {'external_gateway_info': dict(network_id=network_id)}
601 router = client.update_router(router['id'], **kwargs)['router']
602 return router
603 else:
604 raise Exception("Neither of 'public_router_id' or "
605 "'public_network_id' has been defined.")
606
607 def _create_router(self, client=None, tenant_id=None,
608 namestart='router-smoke'):
609 if not client:
610 client = self.routers_client
611 if not tenant_id:
612 tenant_id = client.tenant_id
613 name = data_utils.rand_name(namestart)
614 result = client.create_router(name=name,
615 admin_state_up=True,
616 tenant_id=tenant_id)
617 router = result['router']
618 self.assertEqual(router['name'], name)
619 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
620 client.delete_router,
621 router['id'])
622 return router
623
624 def _update_router_admin_state(self, router, admin_state_up):
625 kwargs = dict(admin_state_up=admin_state_up)
626 router = self.routers_client.update_router(
627 router['id'], **kwargs)['router']
628 self.assertEqual(admin_state_up, router['admin_state_up'])
629
630 def create_networks(self, networks_client=None,
631 routers_client=None, subnets_client=None,
632 tenant_id=None, dns_nameservers=None,
633 port_security_enabled=True):
634 """Create a network with a subnet connected to a router.
635
636 The baremetal driver is a special case since all nodes are
637 on the same shared network.
638
639 :param tenant_id: id of tenant to create resources in.
640 :param dns_nameservers: list of dns servers to send to subnet.
641 :returns: network, subnet, router
642 """
643 if CONF.network.shared_physical_network:
644 # NOTE(Shrews): This exception is for environments where tenant
645 # credential isolation is available, but network separation is
646 # not (the current baremetal case). Likely can be removed when
647 # test account mgmt is reworked:
648 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
649 if not CONF.compute.fixed_network_name:
650 m = 'fixed_network_name must be specified in config'
651 raise lib_exc.InvalidConfiguration(m)
Goutham Pacha Ravi37ee6772019-10-18 12:53:22 -0700652 network = self._get_network_by_name_or_id(
Andrea Frittolif4510a12017-03-07 19:17:11 +0000653 CONF.compute.fixed_network_name)
654 router = None
655 subnet = None
656 else:
Roman Popelka1118f3e2022-03-21 09:18:53 +0100657 network = self.create_network(
Andrea Frittolif4510a12017-03-07 19:17:11 +0000658 networks_client=networks_client,
659 tenant_id=tenant_id,
660 port_security_enabled=port_security_enabled)
661 router = self._get_router(client=routers_client,
662 tenant_id=tenant_id)
663 subnet_kwargs = dict(network=network,
664 subnets_client=subnets_client,
665 routers_client=routers_client)
666 # use explicit check because empty list is a valid option
667 if dns_nameservers is not None:
668 subnet_kwargs['dns_nameservers'] = dns_nameservers
669 subnet = self._create_subnet(**subnet_kwargs)
670 if not routers_client:
671 routers_client = self.routers_client
672 router_id = router['id']
673 routers_client.add_router_interface(router_id,
674 subnet_id=subnet['id'])
675
676 # save a cleanup job to remove this association between
677 # router and subnet
678 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
679 routers_client.remove_router_interface, router_id,
680 subnet_id=subnet['id'])
681 return network, subnet, router