blob: e78643c642e6ddc8dd7fb6ef97f13ef860db685e [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
Sean Dague6dbc6da2013-05-08 17:49:46 -04002# 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
Sean Dague6dbc6da2013-05-08 17:49:46 -040017import subprocess
18
Sean Dague6dbc6da2013-05-08 17:49:46 -040019import netaddr
Doug Hellmann583ce2c2015-03-11 14:55:46 +000020from oslo_log import log
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +030021from oslo_serialization import jsonutils as json
Yatin Kumbhareee4924c2016-06-09 15:12:06 +053022from oslo_utils import netutils
Sean Dague6dbc6da2013-05-08 17:49:46 -040023
lanoux5fc14522015-09-21 08:17:35 +000024from tempest.common import compute
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -070025from tempest.common import image as common_image
Masayuki Igawa4ded9f02014-02-17 15:05:59 +090026from tempest.common.utils.linux import remote_client
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +000027from tempest.common.utils import net_utils
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +000028from tempest.common import waiters
Matthew Treinish6c072292014-01-29 19:15:52 +000029from tempest import config
Giulio Fidente92f77192013-08-26 17:13:28 +020030from tempest import exceptions
Ghanshyam Mann09c4eb92019-06-04 13:07:12 +000031from tempest.lib.common import api_microversion_fixture
32from tempest.lib.common import api_version_utils
Ken'ichi Ohmichibe4fb502017-03-10 10:04:48 -080033from tempest.lib.common.utils import data_utils
Jordan Pittier9e227c52016-02-09 14:35:18 +010034from tempest.lib.common.utils import test_utils
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050035from tempest.lib import exceptions as lib_exc
Sean Dague6dbc6da2013-05-08 17:49:46 -040036import tempest.test
Sean Dague6dbc6da2013-05-08 17:49:46 -040037
Matthew Treinish6c072292014-01-29 19:15:52 +000038CONF = config.CONF
Sean Dague6dbc6da2013-05-08 17:49:46 -040039
Attila Fazekasfb7552a2013-08-27 13:02:26 +020040LOG = log.getLogger(__name__)
41
Ghanshyam Mann09c4eb92019-06-04 13:07:12 +000042LATEST_MICROVERSION = 'latest'
43
Sean Dague6dbc6da2013-05-08 17:49:46 -040044
Andrea Frittoli2e733b52014-07-16 14:12:11 +010045class ScenarioTest(tempest.test.BaseTestCase):
Andrea Frittoli486ede72014-09-25 11:50:05 +010046 """Base class for scenario tests. Uses tempest own clients. """
Andrea Frittoli2e733b52014-07-16 14:12:11 +010047
Andrea Frittolib21de6c2015-02-06 20:12:38 +000048 credentials = ['primary']
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000049
Ghanshyam Mann09c4eb92019-06-04 13:07:12 +000050 compute_min_microversion = None
51 compute_max_microversion = LATEST_MICROVERSION
52 volume_min_microversion = None
53 volume_max_microversion = LATEST_MICROVERSION
54 placement_min_microversion = None
55 placement_max_microversion = LATEST_MICROVERSION
56
57 @classmethod
58 def skip_checks(cls):
59 super(ScenarioTest, cls).skip_checks()
60 api_version_utils.check_skip_with_microversion(
61 cls.compute_min_microversion, cls.compute_max_microversion,
62 CONF.compute.min_microversion, CONF.compute.max_microversion)
63 api_version_utils.check_skip_with_microversion(
64 cls.volume_min_microversion, cls.volume_max_microversion,
65 CONF.volume.min_microversion, CONF.volume.max_microversion)
66 api_version_utils.check_skip_with_microversion(
67 cls.placement_min_microversion, cls.placement_max_microversion,
68 CONF.placement.min_microversion, CONF.placement.max_microversion)
69
70 @classmethod
71 def resource_setup(cls):
72 super(ScenarioTest, cls).resource_setup()
73 cls.compute_request_microversion = (
74 api_version_utils.select_request_microversion(
75 cls.compute_min_microversion,
76 CONF.compute.min_microversion))
77 cls.volume_request_microversion = (
78 api_version_utils.select_request_microversion(
79 cls.volume_min_microversion,
80 CONF.volume.min_microversion))
81 cls.placement_request_microversion = (
82 api_version_utils.select_request_microversion(
83 cls.placement_min_microversion,
84 CONF.placement.min_microversion))
85
86 def setUp(self):
87 super(ScenarioTest, self).setUp()
88 self.useFixture(api_microversion_fixture.APIMicroversionFixture(
89 compute_microversion=self.compute_request_microversion,
90 volume_microversion=self.volume_request_microversion,
91 placement_microversion=self.placement_request_microversion))
92
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000093 @classmethod
94 def setup_clients(cls):
95 super(ScenarioTest, cls).setup_clients()
Andrea Frittoli247058f2014-07-16 16:09:22 +010096 # Clients (in alphabetical order)
jeremy.zhang0343be52017-05-25 21:29:57 +080097 cls.flavors_client = cls.os_primary.flavors_client
John Warrene74890a2015-11-11 15:18:01 -050098 cls.compute_floating_ips_client = (
jeremy.zhang0343be52017-05-25 21:29:57 +080099 cls.os_primary.compute_floating_ips_client)
Jordan Pittier1d2e40f2016-01-05 18:49:14 +0100100 if CONF.service_available.glance:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400101 # Check if glance v1 is available to determine which client to use.
102 if CONF.image_feature_enabled.api_v1:
jeremy.zhang0343be52017-05-25 21:29:57 +0800103 cls.image_client = cls.os_primary.image_client
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400104 elif CONF.image_feature_enabled.api_v2:
jeremy.zhang0343be52017-05-25 21:29:57 +0800105 cls.image_client = cls.os_primary.image_client_v2
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400106 else:
Matthew Treinish4217a702016-10-07 17:27:11 -0400107 raise lib_exc.InvalidConfiguration(
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400108 'Either api_v1 or api_v2 must be True in '
109 '[image-feature-enabled].')
nithya-ganesan882595e2014-07-29 18:51:07 +0000110 # Compute image client
jeremy.zhang0343be52017-05-25 21:29:57 +0800111 cls.compute_images_client = cls.os_primary.compute_images_client
112 cls.keypairs_client = cls.os_primary.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100113 # Nova security groups client
John Warrenf2345512015-12-10 13:39:30 -0500114 cls.compute_security_groups_client = (
jeremy.zhang0343be52017-05-25 21:29:57 +0800115 cls.os_primary.compute_security_groups_client)
John Warren5cdbf422016-01-05 12:42:43 -0500116 cls.compute_security_group_rules_client = (
jeremy.zhang0343be52017-05-25 21:29:57 +0800117 cls.os_primary.compute_security_group_rules_client)
118 cls.servers_client = cls.os_primary.servers_client
119 cls.interface_client = cls.os_primary.interfaces_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300120 # Neutron network client
jeremy.zhang0343be52017-05-25 21:29:57 +0800121 cls.networks_client = cls.os_primary.networks_client
122 cls.ports_client = cls.os_primary.ports_client
123 cls.routers_client = cls.os_primary.routers_client
124 cls.subnets_client = cls.os_primary.subnets_client
125 cls.floating_ips_client = cls.os_primary.floating_ips_client
126 cls.security_groups_client = cls.os_primary.security_groups_client
John Warren456d9ae2016-01-12 15:36:33 -0500127 cls.security_group_rules_client = (
jeremy.zhang0343be52017-05-25 21:29:57 +0800128 cls.os_primary.security_group_rules_client)
Andrea Frittolia6b30152017-08-04 10:46:10 +0100129 # Use the latest available volume clients
130 if CONF.service_available.cinder:
131 cls.volumes_client = cls.os_primary.volumes_client_latest
132 cls.snapshots_client = cls.os_primary.snapshots_client_latest
lkuchlane20e6a82018-05-08 11:28:46 +0300133 cls.backups_client = cls.os_primary.backups_client_latest
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300134
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200135 # ## Test functions library
136 #
137 # The create_[resource] functions only return body and discard the
138 # resp part which is not used in scenario tests
Andrea Frittoli247058f2014-07-16 16:09:22 +0100139
zhufl1e446b52017-10-16 16:54:57 +0800140 def create_port(self, network_id, client=None, **kwargs):
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300141 if not client:
142 client = self.ports_client
zhufl1e446b52017-10-16 16:54:57 +0800143 name = data_utils.rand_name(self.__class__.__name__)
Edan David408a97b2018-01-15 03:52:15 -0500144 if CONF.network.port_vnic_type and 'binding:vnic_type' not in kwargs:
145 kwargs['binding:vnic_type'] = CONF.network.port_vnic_type
146 if CONF.network.port_profile and 'binding:profile' not in kwargs:
147 kwargs['binding:profile'] = CONF.network.port_profile
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300148 result = client.create_port(
149 name=name,
150 network_id=network_id,
151 **kwargs)
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300152 port = result['port']
153 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
154 client.delete_port, port['id'])
155 return port
156
Yair Frieddb6c9e92014-08-06 08:53:13 +0300157 def create_keypair(self, client=None):
158 if not client:
159 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100160 name = data_utils.rand_name(self.__class__.__name__)
161 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000162 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300163 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900164 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100165
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530166 def create_server(self, name=None, image_id=None, flavor=None,
zhufl13c9c892017-02-10 12:04:07 +0800167 validatable=False, wait_until='ACTIVE',
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200168 clients=None, **kwargs):
lanoux5fc14522015-09-21 08:17:35 +0000169 """Wrapper utility that returns a test server.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100170
lanoux5fc14522015-09-21 08:17:35 +0000171 This wrapper utility calls the common create test server and
172 returns a test server. The purpose of this wrapper is to minimize
173 the impact on the code of the tests already using this
174 function.
Noam Angel6e309952019-01-27 05:52:40 +0000175
176 :param **kwargs:
177 See extra parameters below
178
179 :Keyword Arguments:
180 * *vnic_type* (``string``) --
181 used when launching instances with pre-configured ports.
182 Examples:
183 normal: a traditional virtual port that is either attached
184 to a linux bridge or an openvswitch bridge on a
185 compute node.
186 direct: an SR-IOV port that is directly attached to a VM
187 macvtap: an SR-IOV port that is attached to a VM via a macvtap
188 device.
189 Defaults to ``CONF.network.port_vnic_type``.
190 * *port_profile* (``dict``) --
191 This attribute is a dictionary that can be used (with admin
192 credentials) to supply information influencing the binding of
193 the port.
194 example: port_profile = "capabilities:[switchdev]"
195 Defaults to ``CONF.network.port_profile``.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100196 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100197
lanoux5fc14522015-09-21 08:17:35 +0000198 # NOTE(jlanoux): As a first step, ssh checks in the scenario
199 # tests need to be run regardless of the run_validation and
200 # validatable parameters and thus until the ssh validation job
201 # becomes voting in CI. The test resources management and IP
202 # association are taken care of in the scenario tests.
203 # Therefore, the validatable parameter is set to false in all
204 # those tests. In this way create_server just return a standard
205 # server and the scenario tests always perform ssh checks.
206
207 # Needed for the cross_tenant_traffic test:
208 if clients is None:
jeremy.zhang0343be52017-05-25 21:29:57 +0800209 clients = self.os_primary
lanoux5fc14522015-09-21 08:17:35 +0000210
zhufl24208c22016-10-25 15:23:48 +0800211 if name is None:
212 name = data_utils.rand_name(self.__class__.__name__ + "-server")
213
Noam Angel6e309952019-01-27 05:52:40 +0000214 vnic_type = kwargs.pop('vnic_type', CONF.network.port_vnic_type)
215 profile = kwargs.pop('port_profile', CONF.network.port_profile)
lanoux5fc14522015-09-21 08:17:35 +0000216
Lenny Verkhovskyfe3a03f2018-02-28 10:19:37 +0000217 # If vnic_type or profile are configured create port for
lanoux5fc14522015-09-21 08:17:35 +0000218 # every network
Lenny Verkhovskyfe3a03f2018-02-28 10:19:37 +0000219 if vnic_type or profile:
lanoux5fc14522015-09-21 08:17:35 +0000220 ports = []
Lenny Verkhovskyfe3a03f2018-02-28 10:19:37 +0000221 create_port_body = {}
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300222
Lenny Verkhovskyfe3a03f2018-02-28 10:19:37 +0000223 if vnic_type:
224 create_port_body['binding:vnic_type'] = vnic_type
225
226 if profile:
227 create_port_body['binding:profile'] = profile
228
lanoux5fc14522015-09-21 08:17:35 +0000229 if kwargs:
230 # Convert security group names to security group ids
231 # to pass to create_port
232 if 'security_groups' in kwargs:
Thiago Paiva66cded22016-08-15 14:55:58 -0300233 security_groups = \
John Warrenf9606e92015-12-10 12:12:42 -0500234 clients.security_groups_client.list_security_groups(
lanoux5fc14522015-09-21 08:17:35 +0000235 ).get('security_groups')
236 sec_dict = dict([(s['name'], s['id'])
afazekas40fcb9b2019-03-08 11:25:11 +0100237 for s in security_groups])
lanoux5fc14522015-09-21 08:17:35 +0000238
239 sec_groups_names = [s['name'] for s in kwargs.pop(
240 'security_groups')]
241 security_groups_ids = [sec_dict[s]
242 for s in sec_groups_names]
243
244 if security_groups_ids:
245 create_port_body[
246 'security_groups'] = security_groups_ids
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300247 networks = kwargs.pop('networks', [])
248 else:
249 networks = []
lanoux5fc14522015-09-21 08:17:35 +0000250
251 # If there are no networks passed to us we look up
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300252 # for the project's private networks and create a port.
253 # The same behaviour as we would expect when passing
254 # the call to the clients with no networks
lanoux5fc14522015-09-21 08:17:35 +0000255 if not networks:
256 networks = clients.networks_client.list_networks(
Lenny Verkhovsky136376f2016-06-29 14:33:34 +0300257 **{'router:external': False, 'fields': 'id'})['networks']
258
259 # It's net['uuid'] if networks come from kwargs
260 # and net['id'] if they come from
261 # clients.networks_client.list_networks
lanoux5fc14522015-09-21 08:17:35 +0000262 for net in networks:
Lenny Verkhovsky97f7cea2016-08-15 13:29:48 +0000263 net_id = net.get('uuid', net.get('id'))
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300264 if 'port' not in net:
zhufl1e446b52017-10-16 16:54:57 +0800265 port = self.create_port(network_id=net_id,
266 client=clients.ports_client,
267 **create_port_body)
Lenny Verkhovsky69363502016-07-17 16:33:33 +0300268 ports.append({'port': port['id']})
269 else:
270 ports.append({'port': net['port']})
lanoux5fc14522015-09-21 08:17:35 +0000271 if ports:
272 kwargs['networks'] = ports
273 self.ports = ports
274
275 tenant_network = self.get_tenant_network()
276
Marc Koderer979e4942016-12-08 10:07:59 +0100277 if CONF.compute.compute_volume_common_az:
278 kwargs.setdefault('availability_zone',
279 CONF.compute.compute_volume_common_az)
280
Ferenc Horváthbce1fcf2017-06-07 11:19:51 +0200281 body, _ = compute.create_test_server(
lanoux5fc14522015-09-21 08:17:35 +0000282 clients,
283 tenant_network=tenant_network,
284 wait_until=wait_until,
Anusha Ramineni9aaef8b2016-01-19 10:56:40 +0530285 name=name, flavor=flavor,
286 image_id=image_id, **kwargs)
lanoux5fc14522015-09-21 08:17:35 +0000287
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200288 self.addCleanup(waiters.wait_for_server_termination,
289 clients.servers_client, body['id'])
290 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
291 clients.servers_client.delete_server, body['id'])
lanoux5fc14522015-09-21 08:17:35 +0000292 server = clients.servers_client.show_server(body['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100293 return server
294
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100295 def create_volume(self, size=None, name=None, snapshot_id=None,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100296 imageRef=None, volume_type=None):
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700297 if size is None:
298 size = CONF.volume.volume_size
Nuno Santosb746d992016-11-17 15:41:55 -0500299 if imageRef:
zhufl66275c22018-03-28 15:32:14 +0800300 if CONF.image_feature_enabled.api_v1:
301 resp = self.image_client.check_image(imageRef)
302 image = common_image.get_image_meta_from_headers(resp)
303 else:
304 image = self.image_client.show_image(imageRef)
305 min_disk = image.get('min_disk')
Nuno Santosb746d992016-11-17 15:41:55 -0500306 size = max(size, min_disk)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100307 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800308 name = data_utils.rand_name(self.__class__.__name__ + "-volume")
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900309 kwargs = {'display_name': name,
310 'snapshot_id': snapshot_id,
311 'imageRef': imageRef,
Ken'ichi Ohmichiadb905e2016-08-26 15:16:23 -0700312 'volume_type': volume_type,
313 'size': size}
Marc Koderer979e4942016-12-08 10:07:59 +0100314
315 if CONF.compute.compute_volume_common_az:
316 kwargs.setdefault('availability_zone',
317 CONF.compute.compute_volume_common_az)
318
Ghanshyam8fc0ed22015-12-18 10:25:14 +0900319 volume = self.volumes_client.create_volume(**kwargs)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700320
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100321 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
322 volume['id'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100323 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Jordan Pittier5e1741c2016-03-02 18:25:51 +0100324 self.volumes_client.delete_volume, volume['id'])
lkuchlan5cbc00a2017-03-26 11:49:54 +0300325 self.assertEqual(name, volume['name'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200326 waiters.wait_for_volume_resource_status(self.volumes_client,
327 volume['id'], 'available')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100328 # The volume retrieved on creation has a non-up-to-date status.
329 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000330 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100331 return volume
332
lkuchlane20e6a82018-05-08 11:28:46 +0300333 def create_backup(self, volume_id, name=None, description=None,
334 force=False, snapshot_id=None, incremental=False,
335 container=None):
336
337 name = name or data_utils.rand_name(
338 self.__class__.__name__ + "-backup")
339 kwargs = {'name': name,
340 'description': description,
341 'force': force,
342 'snapshot_id': snapshot_id,
343 'incremental': incremental,
344 'container': container}
345 backup = self.backups_client.create_backup(volume_id=volume_id,
346 **kwargs)['backup']
347 self.addCleanup(self.backups_client.delete_backup, backup['id'])
348 waiters.wait_for_volume_resource_status(self.backups_client,
349 backup['id'], 'available')
350 return backup
351
352 def restore_backup(self, backup_id):
353 restore = self.backups_client.restore_backup(backup_id)['restore']
354 self.addCleanup(self.volumes_client.delete_volume,
355 restore['volume_id'])
356 waiters.wait_for_volume_resource_status(self.backups_client,
357 backup_id, 'available')
358 waiters.wait_for_volume_resource_status(self.volumes_client,
359 restore['volume_id'],
360 'available')
361 self.assertEqual(backup_id, restore['backup_id'])
362 return restore
363
lkuchlan73ed1f32017-07-06 16:22:12 +0300364 def create_volume_snapshot(self, volume_id, name=None, description=None,
365 metadata=None, force=False):
366 name = name or data_utils.rand_name(
367 self.__class__.__name__ + '-snapshot')
368 snapshot = self.snapshots_client.create_snapshot(
369 volume_id=volume_id,
370 force=force,
371 display_name=name,
372 description=description,
373 metadata=metadata)['snapshot']
374 self.addCleanup(self.snapshots_client.wait_for_resource_deletion,
375 snapshot['id'])
376 self.addCleanup(self.snapshots_client.delete_snapshot, snapshot['id'])
377 waiters.wait_for_volume_resource_status(self.snapshots_client,
378 snapshot['id'], 'available')
Benny Kopilov11b28002017-12-19 12:46:19 +0200379 snapshot = self.snapshots_client.show_snapshot(
380 snapshot['id'])['snapshot']
lkuchlan73ed1f32017-07-06 16:22:12 +0300381 return snapshot
382
Lee Yarwoodbe64e1a2019-04-09 14:02:12 +0100383 def _cleanup_volume_type(self, volume_type):
384 """Clean up a given volume type.
385
386 Ensuring all volumes associated to a type are first removed before
387 attempting to remove the type itself. This includes any image volume
388 cache volumes stored in a separate tenant to the original volumes
389 created from the type.
390 """
391 admin_volume_type_client = self.os_admin.volume_types_client_latest
392 admin_volumes_client = self.os_admin.volumes_client_latest
393 volumes = admin_volumes_client.list_volumes(
394 detail=True, params={'all_tenants': 1})['volumes']
395 type_name = volume_type['name']
396 for volume in [v for v in volumes if v['volume_type'] == type_name]:
397 test_utils.call_and_ignore_notfound_exc(
398 admin_volumes_client.delete_volume, volume['id'])
399 admin_volumes_client.wait_for_resource_deletion(volume['id'])
400 admin_volume_type_client.delete_volume_type(volume_type['id'])
401
scottda61f68ac2016-06-07 12:07:55 -0600402 def create_volume_type(self, client=None, name=None, backend_name=None):
403 if not client:
ghanshyam6c682ff2018-08-06 09:54:45 +0000404 client = self.os_admin.volume_types_client_latest
Matt Riedemann514495b2019-05-04 17:34:12 +0000405 if not name:
406 class_name = self.__class__.__name__
407 name = data_utils.rand_name(class_name + '-volume-type')
408 randomized_name = data_utils.rand_name('scenario-type-' + name)
scottda61f68ac2016-06-07 12:07:55 -0600409
410 LOG.debug("Creating a volume type: %s on backend %s",
411 randomized_name, backend_name)
412 extra_specs = {}
413 if backend_name:
414 extra_specs = {"volume_backend_name": backend_name}
415
lkuchlanbbabe542017-09-26 10:47:23 +0300416 volume_type = client.create_volume_type(
417 name=randomized_name, extra_specs=extra_specs)['volume_type']
Lee Yarwoodbe64e1a2019-04-09 14:02:12 +0100418 self.addCleanup(self._cleanup_volume_type, volume_type)
scottda61f68ac2016-06-07 12:07:55 -0600419 return volume_type
420
Yair Fried1fc32a12014-08-04 09:11:30 +0300421 def _create_loginable_secgroup_rule(self, secgroup_id=None):
John Warrenf2345512015-12-10 13:39:30 -0500422 _client = self.compute_security_groups_client
John Warren5cdbf422016-01-05 12:42:43 -0500423 _client_rules = self.compute_security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100424 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900425 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100426 for sg in sgs:
427 if sg['name'] == 'default':
428 secgroup_id = sg['id']
429
430 # These rules are intended to permit inbound ssh and icmp
431 # traffic from all sources, so no group_id is provided.
432 # Setting a group_id would only permit traffic from ports
433 # belonging to the same security group.
434 rulesets = [
435 {
436 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000437 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100438 'from_port': 22,
439 'to_port': 22,
440 'cidr': '0.0.0.0/0',
441 },
442 {
443 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000444 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100445 'from_port': -1,
446 'to_port': -1,
447 'cidr': '0.0.0.0/0',
448 }
449 ]
450 rules = list()
451 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000452 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900453 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100454 rules.append(sg_rule)
455 return rules
456
Yair Fried1fc32a12014-08-04 09:11:30 +0300457 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100458 # Create security group
459 sg_name = data_utils.rand_name(self.__class__.__name__)
460 sg_desc = sg_name + " description"
John Warrenf2345512015-12-10 13:39:30 -0500461 secgroup = self.compute_security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900462 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100463 self.assertEqual(secgroup['name'], sg_name)
464 self.assertEqual(secgroup['description'], sg_desc)
John Warrenf2345512015-12-10 13:39:30 -0500465 self.addCleanup(
Jordan Pittier9e227c52016-02-09 14:35:18 +0100466 test_utils.call_and_ignore_notfound_exc,
John Warrenf2345512015-12-10 13:39:30 -0500467 self.compute_security_groups_client.delete_security_group,
468 secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100469
470 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300471 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100472
473 return secgroup
474
zhuflf52c7592017-05-25 13:55:24 +0800475 def get_remote_client(self, ip_address, username=None, private_key=None,
476 server=None):
JordanP3fe2dc32014-11-17 13:06:01 +0100477 """Get a SSH client to a remote server
478
Sergey Vilgelmeac094a2018-11-21 18:27:51 -0600479 :param ip_address: the server floating or fixed IP address to use
480 for ssh validation
481 :param username: name of the Linux account on the remote server
482 :param private_key: the SSH private key to use
483 :param server: server dict, used for debugging purposes
484 :return: a RemoteClient object
JordanP3fe2dc32014-11-17 13:06:01 +0100485 """
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700486
Andrea Frittoli247058f2014-07-16 16:09:22 +0100487 if username is None:
lanoux283273b2015-12-04 03:01:54 -0800488 username = CONF.validation.image_ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800489 # Set this with 'keypair' or others to log in with keypair or
490 # username/password.
lanoux5fc14522015-09-21 08:17:35 +0000491 if CONF.validation.auth_method == 'keypair':
wantwatering896300c2015-03-27 15:17:42 +0800492 password = None
493 if private_key is None:
494 private_key = self.keypair['private_key']
495 else:
lanoux283273b2015-12-04 03:01:54 -0800496 password = CONF.validation.image_ssh_password
wantwatering896300c2015-03-27 15:17:42 +0800497 private_key = None
zhuflf52c7592017-05-25 13:55:24 +0800498 linux_client = remote_client.RemoteClient(
499 ip_address, username, pkey=private_key, password=password,
500 server=server, servers_client=self.servers_client)
501 linux_client.validate_authentication()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100502 return linux_client
503
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000504 def _image_create(self, name, fmt, path,
505 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900506 if properties is None:
507 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100508 name = data_utils.rand_name('%s-' % name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100509 params = {
510 'name': name,
511 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000512 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100513 }
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400514 if CONF.image_feature_enabled.api_v1:
515 params['is_public'] = 'False'
516 params['properties'] = properties
Ken'ichi Ohmichi02bcdf32016-06-17 16:41:26 -0700517 params = {'headers': common_image.image_meta_to_headers(**params)}
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400518 else:
519 params['visibility'] = 'private'
520 # Additional properties are flattened out in the v2 API.
521 params.update(properties)
522 body = self.image_client.create_image(**params)
523 image = body['image'] if 'image' in body else body
Andrea Frittoli247058f2014-07-16 16:09:22 +0100524 self.addCleanup(self.image_client.delete_image, image['id'])
525 self.assertEqual("queued", image['status'])
zhang.leia4b1cef2016-03-01 10:50:01 +0800526 with open(path, 'rb') as image_file:
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400527 if CONF.image_feature_enabled.api_v1:
528 self.image_client.update_image(image['id'], data=image_file)
529 else:
530 self.image_client.store_image_file(image['id'], image_file)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100531 return image['id']
532
533 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300534 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100535 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
536 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
537 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300538 img_container_format = CONF.scenario.img_container_format
539 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000540 img_properties = CONF.scenario.img_properties
PranaliD2aa523c2016-06-07 03:54:34 -0400541 LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, "
Jordan Pittier525ec712016-12-07 17:51:26 +0100542 "properties: %s, ami: %s, ari: %s, aki: %s",
543 img_path, img_container_format, img_disk_format,
544 img_properties, ami_img_path, ari_img_path, aki_img_path)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100545 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100546 image = self._image_create('scenario-img',
547 img_container_format,
548 img_path,
549 disk_format=img_disk_format,
550 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100551 except IOError:
Ryan Hsue5107be2015-12-03 13:55:03 -0800552 LOG.warning(
553 "A(n) %s image was not found. Retrying with uec image.",
554 img_disk_format)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100555 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
556 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000557 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100558 image = self._image_create('scenario-ami', 'ami',
559 path=ami_img_path,
560 properties=properties)
Jordan Pittier525ec712016-12-07 17:51:26 +0100561 LOG.debug("image:%s", image)
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100562
563 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100564
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700565 def _log_console_output(self, servers=None, client=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400566 if not CONF.compute_feature_enabled.console_output:
567 LOG.debug('Console output not supported, cannot log')
568 return
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700569 client = client or self.servers_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100570 if not servers:
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700571 servers = client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100572 servers = servers['servers']
573 for server in servers:
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100574 try:
Ihar Hrachyshkaa9dca2b2017-04-04 14:17:11 -0700575 console_output = client.get_console_output(
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100576 server['id'])['output']
577 LOG.debug('Console output for %s\nbody=\n%s',
578 server['id'], console_output)
579 except lib_exc.NotFound:
Attila Fazekase1360482016-11-10 11:28:08 +0100580 LOG.debug("Server %s disappeared(deleted) while looking "
Attila Fazekas9a5a1122016-11-08 10:24:57 +0100581 "for the console log", server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100582
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000583 def _log_net_info(self, exc):
584 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300585 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000586 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000587
nithya-ganesan882595e2014-07-29 18:51:07 +0000588 def create_server_snapshot(self, server, name=None):
589 # Glance client
590 _image_client = self.image_client
591 # Compute client
Ghanshyamae76c122015-12-22 13:41:35 +0900592 _images_client = self.compute_images_client
nithya-ganesan882595e2014-07-29 18:51:07 +0000593 if name is None:
zhuflf9d95722016-10-19 16:06:17 +0800594 name = data_utils.rand_name(self.__class__.__name__ + 'snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000595 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000596 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500597 image_id = image.response['location'].split('images/')[1]
Yaroslav Lobankov2fea4052016-04-19 15:05:57 +0300598 waiters.wait_for_image_status(_image_client, image_id, 'active')
Jordan Pittierf672b7d2016-06-20 18:50:40 +0200599
600 self.addCleanup(_image_client.wait_for_resource_deletion,
601 image_id)
602 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
603 _image_client.delete_image, image_id)
604
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400605 if CONF.image_feature_enabled.api_v1:
606 # In glance v1 the additional properties are stored in the headers.
Ken'ichi Ohmichi01151e82016-06-10 11:19:52 -0700607 resp = _image_client.check_image(image_id)
608 snapshot_image = common_image.get_image_meta_from_headers(resp)
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400609 image_props = snapshot_image.get('properties', {})
610 else:
611 # In glance v2 the additional properties are flattened.
612 snapshot_image = _image_client.show_image(image_id)
613 image_props = snapshot_image
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300614
Matt Riedemann2aa19d42016-06-06 17:45:41 -0400615 bdm = image_props.get('block_device_mapping')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300616 if bdm:
617 bdm = json.loads(bdm)
618 if bdm and 'snapshot_id' in bdm[0]:
619 snapshot_id = bdm[0]['snapshot_id']
620 self.addCleanup(
621 self.snapshots_client.wait_for_resource_deletion,
622 snapshot_id)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100623 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
624 self.snapshots_client.delete_snapshot,
625 snapshot_id)
lkuchlan52d7b0d2016-11-07 20:53:19 +0200626 waiters.wait_for_volume_resource_status(self.snapshots_client,
627 snapshot_id,
628 'available')
nithya-ganesan882595e2014-07-29 18:51:07 +0000629 image_name = snapshot_image['name']
630 self.assertEqual(name, image_name)
631 LOG.debug("Created snapshot image %s for server %s",
632 image_name, server['name'])
633 return snapshot_image
634
Jordan Pittier7cf64762015-10-14 15:01:12 +0200635 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000636 volume = self.servers_client.attach_volume(
Paras Babbar4b45f9e2019-12-11 16:51:57 -0500637 server['id'], volumeId=volume_to_attach['id'])['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200638 self.assertEqual(volume_to_attach['id'], volume['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200639 waiters.wait_for_volume_resource_status(self.volumes_client,
640 volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900641
Jordan Pittier7cf64762015-10-14 15:01:12 +0200642 # Return the updated volume after the attachment
643 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900644
Jordan Pittier7cf64762015-10-14 15:01:12 +0200645 def nova_volume_detach(self, server, volume):
646 self.servers_client.detach_volume(server['id'], volume['id'])
lkuchlan52d7b0d2016-11-07 20:53:19 +0200647 waiters.wait_for_volume_resource_status(self.volumes_client,
648 volume['id'], 'available')
Jordan Pittier7cf64762015-10-14 15:01:12 +0200649
Steven Hardyda2a8352014-10-02 12:52:20 +0100650 def ping_ip_address(self, ip_address, should_succeed=True,
zhufl0ec74c42017-11-15 14:02:28 +0800651 ping_timeout=None, mtu=None, server=None):
lanoux5fc14522015-09-21 08:17:35 +0000652 timeout = ping_timeout or CONF.validation.ping_timeout
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000653 cmd = ['ping', '-c1', '-w1']
654
655 if mtu:
656 cmd += [
657 # don't fragment
658 '-M', 'do',
659 # ping receives just the size of ICMP payload
660 '-s', str(net_utils.get_ping_payload_size(mtu, 4))
661 ]
662 cmd.append(ip_address)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700663
664 def ping():
665 proc = subprocess.Popen(cmd,
666 stdout=subprocess.PIPE,
667 stderr=subprocess.PIPE)
668 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000669
Aaron Rosena7df13b2014-09-23 09:45:45 -0700670 return (proc.returncode == 0) == should_succeed
671
Jordan Pittier9e227c52016-02-09 14:35:18 +0100672 caller = test_utils.find_test_caller()
Shuquan Huang753629e2015-07-20 08:52:29 +0000673 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
John L. Villalovosa898aec2017-01-13 14:46:46 -0800674 ' expected result is %(should_succeed)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000675 'caller': caller, 'ip': ip_address, 'timeout': timeout,
676 'should_succeed':
677 'reachable' if should_succeed else 'unreachable'
678 })
Jordan Pittier35a63752016-08-30 13:09:12 +0200679 result = test_utils.call_until_true(ping, timeout, 1)
Shuquan Huang753629e2015-07-20 08:52:29 +0000680 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
John L. Villalovosa898aec2017-01-13 14:46:46 -0800681 'ping result is %(result)s', {
Shuquan Huang753629e2015-07-20 08:52:29 +0000682 'caller': caller, 'ip': ip_address, 'timeout': timeout,
683 'result': 'expected' if result else 'unexpected'
684 })
zhufl0ec74c42017-11-15 14:02:28 +0800685 if server:
686 self._log_console_output([server])
Shuquan Huang753629e2015-07-20 08:52:29 +0000687 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700688
Yair Friedae0e73d2014-11-24 11:56:26 +0200689 def check_vm_connectivity(self, ip_address,
690 username=None,
691 private_key=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000692 should_connect=True,
zhufl0ec74c42017-11-15 14:02:28 +0800693 extra_msg="",
694 server=None,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000695 mtu=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000696 """Check server connectivity
697
Yair Friedae0e73d2014-11-24 11:56:26 +0200698 :param ip_address: server to test against
699 :param username: server's ssh username
700 :param private_key: server's ssh private key to be used
701 :param should_connect: True/False indicates positive/negative test
702 positive - attempt ping and ssh
703 negative - attempt ping and fail if succeed
zhufl0ec74c42017-11-15 14:02:28 +0800704 :param extra_msg: Message to help with debugging if ``ping_ip_address``
705 fails
706 :param server: The server whose console to log for debugging
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000707 :param mtu: network MTU to use for connectivity validation
Yair Friedae0e73d2014-11-24 11:56:26 +0200708
709 :raises: AssertError if the result of the connectivity check does
710 not match the value of the should_connect param
711 """
zhufl0ec74c42017-11-15 14:02:28 +0800712 LOG.debug('checking network connections to IP %s with user: %s',
713 ip_address, username)
Yair Friedae0e73d2014-11-24 11:56:26 +0200714 if should_connect:
715 msg = "Timed out waiting for %s to become reachable" % ip_address
716 else:
717 msg = "ip address %s is reachable" % ip_address
zhufl0ec74c42017-11-15 14:02:28 +0800718 if extra_msg:
719 msg = "%s\n%s" % (extra_msg, msg)
Yair Friedae0e73d2014-11-24 11:56:26 +0200720 self.assertTrue(self.ping_ip_address(ip_address,
Ihar Hrachyshkaf9227c02016-09-15 11:16:47 +0000721 should_succeed=should_connect,
zhufl0ec74c42017-11-15 14:02:28 +0800722 mtu=mtu, server=server),
Yair Friedae0e73d2014-11-24 11:56:26 +0200723 msg=msg)
724 if should_connect:
725 # no need to check ssh for negative connectivity
zhufl0ec74c42017-11-15 14:02:28 +0800726 try:
727 self.get_remote_client(ip_address, username, private_key,
728 server=server)
729 except Exception:
730 if not extra_msg:
731 extra_msg = 'Failed to ssh to %s' % ip_address
732 LOG.exception(extra_msg)
733 raise
Yair Friedae0e73d2014-11-24 11:56:26 +0200734
735 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000736 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200737
Marc Koderer3b57d802016-03-22 15:23:31 +0100738 if not pool_name:
739 pool_name = CONF.network.floating_network_name
John Warrene74890a2015-11-11 15:18:01 -0500740 floating_ip = (self.compute_floating_ips_client.
Ken'ichi Ohmichie037a6f2015-12-03 06:41:49 +0000741 create_floating_ip(pool=pool_name)['floating_ip'])
Jordan Pittier9e227c52016-02-09 14:35:18 +0100742 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
John Warrene74890a2015-11-11 15:18:01 -0500743 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200744 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500745 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200746 floating_ip['ip'], thing['id'])
747 return floating_ip
748
Sean Dague20e98612016-01-06 14:33:28 -0500749 def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Slawek Kaplonski79d8b0f2018-07-30 22:43:41 +0200750 private_key=None, server=None):
Sean Dague20e98612016-01-06 14:33:28 -0500751 ssh_client = self.get_remote_client(ip_address,
Slawek Kaplonski79d8b0f2018-07-30 22:43:41 +0200752 private_key=private_key,
753 server=server)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300754 if dev_name is not None:
755 ssh_client.make_fs(dev_name)
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800756 ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name,
757 mount_path))
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300758 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
759 ssh_client.exec_command(cmd_timestamp)
760 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
761 % mount_path)
762 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800763 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300764 return timestamp
765
Sean Dague20e98612016-01-06 14:33:28 -0500766 def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt',
Slawek Kaplonski79d8b0f2018-07-30 22:43:41 +0200767 private_key=None, server=None):
Sean Dague20e98612016-01-06 14:33:28 -0500768 ssh_client = self.get_remote_client(ip_address,
Slawek Kaplonski79d8b0f2018-07-30 22:43:41 +0200769 private_key=private_key,
770 server=server)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300771 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700772 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300773 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
774 % mount_path)
775 if dev_name is not None:
Ken'ichi Ohmichi4e5a69e2017-03-01 18:15:29 -0800776 ssh_client.exec_command('sudo umount %s' % mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300777 return timestamp
778
Sean Dague20e98612016-01-06 14:33:28 -0500779 def get_server_ip(self, server):
780 """Get the server fixed or floating IP.
781
782 Based on the configuration we're in, return a correct ip
783 address for validating that a guest is up.
784 """
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200785 if CONF.validation.connect_method == 'floating':
Sean Dague20e98612016-01-06 14:33:28 -0500786 # The tests calling this method don't have a floating IP
zhufl0892cb22016-05-06 14:46:00 +0800787 # and can't make use of the validation resources. So the
Sean Dague20e98612016-01-06 14:33:28 -0500788 # method is creating the floating IP there.
789 return self.create_floating_ip(server)['ip']
790 elif CONF.validation.connect_method == 'fixed':
Matt Riedemanna7782552016-08-08 16:26:01 -0400791 # Determine the network name to look for based on config or creds
792 # provider network resources.
793 if CONF.validation.network_for_ssh:
794 addresses = server['addresses'][
795 CONF.validation.network_for_ssh]
796 else:
zhufl7b4a7202017-09-28 10:29:27 +0800797 network = self.get_tenant_network()
Matt Riedemanna7782552016-08-08 16:26:01 -0400798 addresses = (server['addresses'][network['name']]
799 if network else [])
Sean Dague20e98612016-01-06 14:33:28 -0500800 for address in addresses:
Federico Ressi2d6bcaa2018-04-11 12:37:36 +0200801 if (address['version'] == CONF.validation.ip_version_for_ssh and # noqa
802 address['OS-EXT-IPS:type'] == 'fixed'):
Sean Dague20e98612016-01-06 14:33:28 -0500803 return address['addr']
zhufl955f82b2016-07-22 11:14:34 +0800804 raise exceptions.ServerUnreachable(server_id=server['id'])
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200805 else:
Matthew Treinish4217a702016-10-07 17:27:11 -0400806 raise lib_exc.InvalidConfiguration()
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200807
zhufl7bc916d2018-08-22 14:47:39 +0800808 @classmethod
809 def get_host_for_server(cls, server_id):
810 server_details = cls.os_admin.servers_client.show_server(server_id)
811 return server_details['server']['OS-EXT-SRV-ATTR:host']
812
Rajat Dhasmanaa8bfa172020-01-14 17:34:44 +0000813 def _get_bdm(self, source_id, source_type, delete_on_termination=False):
814 bd_map_v2 = [{
815 'uuid': source_id,
816 'source_type': source_type,
817 'destination_type': 'volume',
818 'boot_index': 0,
819 'delete_on_termination': delete_on_termination}]
820 return {'block_device_mapping_v2': bd_map_v2}
821
822 def boot_instance_from_resource(self, source_id,
823 source_type,
824 keypair=None,
825 security_group=None,
826 delete_on_termination=False,
827 name=None):
828 create_kwargs = dict()
829 if keypair:
830 create_kwargs['key_name'] = keypair['name']
831 if security_group:
832 create_kwargs['security_groups'] = [
833 {'name': security_group['name']}]
834 create_kwargs.update(self._get_bdm(
835 source_id,
836 source_type,
837 delete_on_termination=delete_on_termination))
838 if name:
839 create_kwargs['name'] = name
840
841 return self.create_server(image_id='', **create_kwargs)
842
843 def create_volume_from_image(self):
844 img_uuid = CONF.compute.image_ref
845 vol_name = data_utils.rand_name(
846 self.__class__.__name__ + '-volume-origin')
847 return self.create_volume(name=vol_name, imageRef=img_uuid)
848
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100849
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100850class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300851 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000852
Yair Fried1fc32a12014-08-04 09:11:30 +0300853 This class provide helpers for network scenario tests, using the neutron
854 API. Helpers from ancestor which use the nova network API are overridden
855 with the neutron API.
856
857 This Class also enforces using Neutron instead of novanetwork.
858 Subclassed tests will be skipped if Neutron is not enabled
859
860 """
861
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000862 credentials = ['primary', 'admin']
863
Yair Fried1fc32a12014-08-04 09:11:30 +0300864 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000865 def skip_checks(cls):
866 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100867 if not CONF.service_available.neutron:
868 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300869
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -0700870 def _create_network(self, networks_client=None,
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +0000871 project_id=None,
Markus Zoeller156b5da2016-07-11 18:10:31 +0200872 namestart='network-smoke-',
Lajos Katonac87a06b2019-01-04 13:21:48 +0100873 port_security_enabled=True, **net_dict):
John Warren94d8faf2015-09-15 12:22:24 -0400874 if not networks_client:
875 networks_client = self.networks_client
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +0000876 if not project_id:
877 project_id = networks_client.project_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300878 name = data_utils.rand_name(namestart)
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +0000879 network_kwargs = dict(name=name, project_id=project_id)
Lajos Katonac87a06b2019-01-04 13:21:48 +0100880 if net_dict:
881 network_kwargs.update(net_dict)
Matt Riedemann039b2fe2016-09-15 16:12:24 -0400882 # Neutron disables port security by default so we have to check the
883 # config before trying to create the network with port_security_enabled
884 if CONF.network_feature_enabled.port_security:
885 network_kwargs['port_security_enabled'] = port_security_enabled
Markus Zoeller156b5da2016-07-11 18:10:31 +0200886 result = networks_client.create_network(**network_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -0500887 network = result['network']
888
889 self.assertEqual(network['name'], name)
Jordan Pittier9e227c52016-02-09 14:35:18 +0100890 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +0800891 networks_client.delete_network,
Steve Heyman33735f22016-05-24 09:28:08 -0500892 network['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300893 return network
894
zhufl5b0a52f2017-10-24 15:48:20 +0800895 def create_subnet(self, network, subnets_client=None,
896 namestart='subnet-smoke', **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000897 """Create a subnet for the given network
898
899 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300900 """
John Warren3961acd2015-10-02 14:38:53 -0400901 if not subnets_client:
902 subnets_client = self.subnets_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300903
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +0000904 def cidr_in_use(cidr, project_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000905 """Check cidr existence
906
lei zhangdd552b22015-11-25 20:41:48 +0800907 :returns: True if subnet with cidr already exist in tenant
908 False else
Yair Fried1fc32a12014-08-04 09:11:30 +0300909 """
jeremy.zhang5870ff12017-05-25 11:24:23 +0800910 cidr_in_use = self.os_admin.subnets_client.list_subnets(
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +0000911 project_id=project_id, cidr=cidr)['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300912 return len(cidr_in_use) != 0
913
Kirill Shileev14113572014-11-21 16:58:02 +0300914 ip_version = kwargs.pop('ip_version', 4)
915
916 if ip_version == 6:
917 tenant_cidr = netaddr.IPNetwork(
Sean Dagueed6e5862016-04-04 10:49:13 -0400918 CONF.network.project_network_v6_cidr)
919 num_bits = CONF.network.project_network_v6_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300920 else:
Sean Dagueed6e5862016-04-04 10:49:13 -0400921 tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
922 num_bits = CONF.network.project_network_mask_bits
Kirill Shileev14113572014-11-21 16:58:02 +0300923
Yair Fried1fc32a12014-08-04 09:11:30 +0300924 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300925 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300926 # Repeatedly attempt subnet creation with sequential cidr
927 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300928 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300929 str_cidr = str(subnet_cidr)
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +0000930 if cidr_in_use(str_cidr, project_id=network['project_id']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300931 continue
932
933 subnet = dict(
934 name=data_utils.rand_name(namestart),
Steve Heyman33735f22016-05-24 09:28:08 -0500935 network_id=network['id'],
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +0000936 project_id=network['project_id'],
Yair Fried1fc32a12014-08-04 09:11:30 +0300937 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300938 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300939 **kwargs
940 )
941 try:
John Warren3961acd2015-10-02 14:38:53 -0400942 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300943 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900944 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300945 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
946 if not is_overlapping_cidr:
947 raise
948 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Steve Heyman33735f22016-05-24 09:28:08 -0500949
950 subnet = result['subnet']
951 self.assertEqual(subnet['cidr'], str_cidr)
952
953 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
954 subnets_client.delete_subnet, subnet['id'])
955
Yair Fried1fc32a12014-08-04 09:11:30 +0300956 return subnet
957
Kirill Shileev14113572014-11-21 16:58:02 +0300958 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Hongbin Lu95a31692018-06-13 23:17:54 +0000959 if ip_addr:
960 ports = self.os_admin.ports_client.list_ports(
961 device_id=server['id'],
962 fixed_ips='ip_address=%s' % ip_addr)['ports']
963 else:
964 ports = self.os_admin.ports_client.list_ports(
965 device_id=server['id'])['ports']
Kobi Samoray166500a2016-10-09 14:42:48 +0300966 # A port can have more than one IP address in some cases.
Sean M. Collins2e896832015-12-15 13:58:47 -0500967 # If the network is dual-stack (IPv4 + IPv6), this port is associated
968 # with 2 subnets
Dmitry Tantsur5c191fa2020-04-14 12:13:09 +0200969
970 def _is_active(port):
971 # NOTE(vsaienko) With Ironic, instances live on separate hardware
972 # servers. Neutron does not bind ports for Ironic instances, as a
973 # result the port remains in the DOWN state. This has been fixed
974 # with the introduction of the networking-baremetal plugin but
975 # it's not mandatory (and is not used on all stable branches).
976 return (port['status'] == 'ACTIVE' or
977 port.get('binding:vnic_type') == 'baremetal')
978
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200979 port_map = [(p["id"], fxip["ip_address"])
980 for p in ports
981 for fxip in p["fixed_ips"]
Federico Ressi2d6bcaa2018-04-11 12:37:36 +0200982 if (netutils.is_valid_ipv4(fxip["ip_address"]) and
Dmitry Tantsur5c191fa2020-04-14 12:13:09 +0200983 _is_active(p))]
Kevin Benton1d0c1dc2016-02-04 14:30:08 -0800984 inactive = [p for p in ports if p['status'] != 'ACTIVE']
985 if inactive:
986 LOG.warning("Instance has ports that are not ACTIVE: %s", inactive)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200987
Masayuki Igawaf9009b42017-04-10 14:49:29 +0900988 self.assertNotEmpty(port_map,
John L. Villalovosb83286f2015-11-04 14:46:57 -0800989 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200990 self.assertEqual(len(port_map), 1,
991 "Found multiple IPv4 addresses: %s. "
992 "Unable to determine which port to target."
993 % port_map)
994 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300995
David Shrewsbury9bac3662014-08-07 15:07:01 -0400996 def _get_network_by_name(self, network_name):
jeremy.zhang5870ff12017-05-25 11:24:23 +0800997 net = self.os_admin.networks_client.list_networks(
Jordan Pittier64e6b442017-02-20 19:29:02 +0100998 name=network_name)['networks']
Ferenc Horváth268ccce2017-06-08 12:39:02 +0200999 self.assertNotEmpty(net,
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001000 "Unable to get network by name: %s" % network_name)
Steve Heyman33735f22016-05-24 09:28:08 -05001001 return net[0]
David Shrewsbury9bac3662014-08-07 15:07:01 -04001002
Yair Friedae0e73d2014-11-24 11:56:26 +02001003 def create_floating_ip(self, thing, external_network_id=None,
1004 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +00001005 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +02001006 if not external_network_id:
1007 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +03001008 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -05001009 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001010 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +03001011 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
1012 else:
1013 ip4 = None
Lukas Piwowarski2385e042020-01-31 12:28:20 +00001014
1015 kwargs = {
1016 'floating_network_id': external_network_id,
1017 'port_id': port_id,
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001018 'tenant_id': thing.get('project_id') or thing['tenant_id'],
Lukas Piwowarski2385e042020-01-31 12:28:20 +00001019 'fixed_ip_address': ip4,
1020 }
1021 if CONF.network.subnet_id:
1022 kwargs['subnet_id'] = CONF.network.subnet_id
1023 result = client.create_floatingip(**kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001024 floating_ip = result['floatingip']
Lukas Piwowarski2385e042020-01-31 12:28:20 +00001025
Jordan Pittier9e227c52016-02-09 14:35:18 +01001026 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
zhoubin508bf20b32017-02-03 09:39:14 +08001027 client.delete_floatingip,
Steve Heyman33735f22016-05-24 09:28:08 -05001028 floating_ip['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001029 return floating_ip
1030
Yair Fried45f92952014-06-26 05:19:19 +03001031 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +00001032 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +03001033
Steve Heyman33735f22016-05-24 09:28:08 -05001034 :param dict floating_ip: floating IP dict to check status
Yair Fried45f92952014-06-26 05:19:19 +03001035 :param status: target status
1036 :raises: AssertionError if status doesn't match
1037 """
Steve Heyman33735f22016-05-24 09:28:08 -05001038 floatingip_id = floating_ip['id']
1039
Carl Baldwina754e2d2014-10-23 22:47:41 +00001040 def refresh():
Martin Kopecf4b5df62020-01-27 09:44:29 +00001041 floating_ip = (self.floating_ips_client.
1042 show_floatingip(floatingip_id)['floatingip'])
1043 if status == floating_ip['status']:
1044 LOG.info("FloatingIP: {fp} is at status: {st}"
1045 .format(fp=floating_ip, st=status))
1046 return status == floating_ip['status']
Carl Baldwina754e2d2014-10-23 22:47:41 +00001047
zhufl4dda94e2017-03-14 16:14:46 +08001048 if not test_utils.call_until_true(refresh,
1049 CONF.network.build_timeout,
1050 CONF.network.build_interval):
1051 floating_ip = self.floating_ips_client.show_floatingip(
1052 floatingip_id)['floatingip']
1053 self.assertEqual(status, floating_ip['status'],
1054 message="FloatingIP: {fp} is at status: {cst}. "
1055 "failed to reach status: {st}"
1056 .format(fp=floating_ip, cst=floating_ip['status'],
1057 st=status))
Yair Fried45f92952014-06-26 05:19:19 +03001058
zhufl420a0192017-09-28 11:04:50 +08001059 def check_tenant_network_connectivity(self, server,
1060 username,
1061 private_key,
1062 should_connect=True,
1063 servers_for_debug=None):
Sean Dagueed6e5862016-04-04 10:49:13 -04001064 if not CONF.network.project_networks_reachable:
Yair Fried1fc32a12014-08-04 09:11:30 +03001065 msg = 'Tenant networks not configured to be reachable.'
1066 LOG.info(msg)
1067 return
1068 # The target login is assumed to have been configured for
1069 # key-based authentication by cloud-init.
1070 try:
Béla Vancsicsb6dfa082017-03-01 10:44:58 +01001071 for ip_addresses in server['addresses'].values():
Yair Fried1fc32a12014-08-04 09:11:30 +03001072 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +09001073 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +02001074 username,
1075 private_key,
1076 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +03001077 except Exception as e:
1078 LOG.exception('Tenant network connectivity check failed')
1079 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +00001080 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +03001081 raise
1082
zhufle9877c62017-10-13 09:38:19 +08001083 def check_remote_connectivity(self, source, dest, should_succeed=True,
Claudiu Belu33c3e602014-08-28 16:38:01 +03001084 nic=None, protocol='icmp'):
1085 """check server connectivity via source ssh connection
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +09001086
Claudiu Belu33c3e602014-08-28 16:38:01 +03001087 :param source: RemoteClient: an ssh connection from which to execute
1088 the check
1089 :param dest: an IP to check connectivity against
1090 :param should_succeed: boolean should connection succeed or not
1091 :param nic: specific network interface to test connectivity from
1092 :param protocol: the protocol used to test connectivity with.
1093 :returns: True, if the connection succeeded and it was expected to
1094 succeed. False otherwise.
Yair Fried1fc32a12014-08-04 09:11:30 +03001095 """
Claudiu Belu33c3e602014-08-28 16:38:01 +03001096 method_name = '%s_check' % protocol
1097 connectivity_checker = getattr(source, method_name)
1098
1099 def connect_remote():
Yair Fried1fc32a12014-08-04 09:11:30 +03001100 try:
Claudiu Belu33c3e602014-08-28 16:38:01 +03001101 connectivity_checker(dest, nic=nic)
Andrey Pavlov64723762015-04-29 06:24:58 +03001102 except lib_exc.SSHExecCommandFailed:
Claudiu Belu33c3e602014-08-28 16:38:01 +03001103 LOG.warning('Failed to check %(protocol)s connectivity for '
1104 'IP %(dest)s via a ssh connection from: %(src)s.',
1105 dict(protocol=protocol, dest=dest,
1106 src=source.ssh_client.host))
Yair Fried1fc32a12014-08-04 09:11:30 +03001107 return not should_succeed
1108 return should_succeed
1109
Claudiu Belu33c3e602014-08-28 16:38:01 +03001110 result = test_utils.call_until_true(connect_remote,
zhufle9877c62017-10-13 09:38:19 +08001111 CONF.validation.ping_timeout, 1)
Ihar Hrachyshkaf9fda2d2017-11-06 13:16:09 -08001112 if result:
1113 return
1114
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +09001115 source_host = source.ssh_client.host
1116 if should_succeed:
1117 msg = "Timed out waiting for %s to become reachable from %s" \
1118 % (dest, source_host)
1119 else:
1120 msg = "%s is reachable from %s" % (dest, source_host)
Ihar Hrachyshkaf9fda2d2017-11-06 13:16:09 -08001121 self._log_console_output()
1122 self.fail(msg)
YAMAMOTO Takashi4c3ebb02017-01-25 16:04:30 +09001123
John Warren456d9ae2016-01-12 15:36:33 -05001124 def _create_security_group(self, security_group_rules_client=None,
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001125 project_id=None,
John Warrenf9606e92015-12-10 12:12:42 -05001126 namestart='secgroup-smoke',
1127 security_groups_client=None):
John Warren456d9ae2016-01-12 15:36:33 -05001128 if security_group_rules_client is None:
1129 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001130 if security_groups_client is None:
1131 security_groups_client = self.security_groups_client
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001132 if project_id is None:
1133 project_id = security_groups_client.project_id
John Warrenf9606e92015-12-10 12:12:42 -05001134 secgroup = self._create_empty_security_group(
1135 namestart=namestart, client=security_groups_client,
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001136 project_id=project_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001137
1138 # Add rules to the security group
John Warrenf9606e92015-12-10 12:12:42 -05001139 rules = self._create_loginable_secgroup_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001140 security_group_rules_client=security_group_rules_client,
1141 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001142 security_groups_client=security_groups_client)
Yair Fried1fc32a12014-08-04 09:11:30 +03001143 for rule in rules:
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001144 self.assertEqual(project_id, rule['project_id'])
Steve Heyman33735f22016-05-24 09:28:08 -05001145 self.assertEqual(secgroup['id'], rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001146 return secgroup
1147
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001148 def _create_empty_security_group(self, client=None, project_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +03001149 namestart='secgroup-smoke'):
1150 """Create a security group without rules.
1151
1152 Default rules will be created:
1153 - IPv4 egress to any
1154 - IPv6 egress to any
1155
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001156 :param project_id: secgroup will be created in this project
Steve Heyman33735f22016-05-24 09:28:08 -05001157 :returns: the created security group
Yair Fried1fc32a12014-08-04 09:11:30 +03001158 """
1159 if client is None:
John Warrenf9606e92015-12-10 12:12:42 -05001160 client = self.security_groups_client
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001161 if not project_id:
1162 project_id = client.project_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001163 sg_name = data_utils.rand_name(namestart)
1164 sg_desc = sg_name + " description"
1165 sg_dict = dict(name=sg_name,
1166 description=sg_desc)
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001167 sg_dict['project_id'] = project_id
David Kranz34e88122014-12-11 15:24:05 -05001168 result = client.create_security_group(**sg_dict)
Steve Heyman33735f22016-05-24 09:28:08 -05001169
1170 secgroup = result['security_group']
1171 self.assertEqual(secgroup['name'], sg_name)
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001172 self.assertEqual(project_id, secgroup['project_id'])
Steve Heyman33735f22016-05-24 09:28:08 -05001173 self.assertEqual(secgroup['description'], sg_desc)
1174
Jordan Pittier9e227c52016-02-09 14:35:18 +01001175 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Steve Heyman33735f22016-05-24 09:28:08 -05001176 client.delete_security_group, secgroup['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001177 return secgroup
1178
John Warren456d9ae2016-01-12 15:36:33 -05001179 def _create_security_group_rule(self, secgroup=None,
1180 sec_group_rules_client=None,
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001181 project_id=None,
John Warrenf9606e92015-12-10 12:12:42 -05001182 security_groups_client=None, **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +03001183 """Create a rule from a dictionary of rule parameters.
1184
1185 Create a rule in a secgroup. if secgroup not defined will search for
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001186 default secgroup in project_id.
Yair Fried1fc32a12014-08-04 09:11:30 +03001187
Steve Heyman33735f22016-05-24 09:28:08 -05001188 :param secgroup: the security group.
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001189 :param project_id: if secgroup not passed -- the tenant in which to
Yair Fried1fc32a12014-08-04 09:11:30 +03001190 search for default secgroup
1191 :param kwargs: a dictionary containing rule parameters:
1192 for example, to allow incoming ssh:
1193 rule = {
1194 direction: 'ingress'
1195 protocol:'tcp',
1196 port_range_min: 22,
1197 port_range_max: 22
1198 }
1199 """
John Warren456d9ae2016-01-12 15:36:33 -05001200 if sec_group_rules_client is None:
1201 sec_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001202 if security_groups_client is None:
1203 security_groups_client = self.security_groups_client
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001204 if not project_id:
1205 project_id = security_groups_client.project_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001206 if secgroup is None:
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001207 # Get default secgroup for project_id
zhuflb0b272e2017-09-22 16:01:46 +08001208 default_secgroups = security_groups_client.list_security_groups(
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001209 name='default', project_id=project_id)['security_groups']
1210 msg = "No default security group for project %s." % (project_id)
zhuflb0b272e2017-09-22 16:01:46 +08001211 self.assertNotEmpty(default_secgroups, msg)
1212 secgroup = default_secgroups[0]
Yair Fried1fc32a12014-08-04 09:11:30 +03001213
Steve Heyman33735f22016-05-24 09:28:08 -05001214 ruleset = dict(security_group_id=secgroup['id'],
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001215 project_id=secgroup['project_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001216 ruleset.update(kwargs)
1217
John Warren456d9ae2016-01-12 15:36:33 -05001218 sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
Steve Heyman33735f22016-05-24 09:28:08 -05001219 sg_rule = sg_rule['security_group_rule']
1220
1221 self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id'])
1222 self.assertEqual(secgroup['id'], sg_rule['security_group_id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001223
1224 return sg_rule
1225
John Warren456d9ae2016-01-12 15:36:33 -05001226 def _create_loginable_secgroup_rule(self, security_group_rules_client=None,
1227 secgroup=None,
John Warrenf9606e92015-12-10 12:12:42 -05001228 security_groups_client=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001229 """Create loginable security group rule
1230
Alex Stafeyevdd5dde92016-05-08 14:35:04 +03001231 This function will create:
1232 1. egress and ingress tcp port 22 allow rule in order to allow ssh
1233 access for ipv4.
1234 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6.
1235 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4.
Yair Fried1fc32a12014-08-04 09:11:30 +03001236 """
1237
John Warren456d9ae2016-01-12 15:36:33 -05001238 if security_group_rules_client is None:
1239 security_group_rules_client = self.security_group_rules_client
John Warrenf9606e92015-12-10 12:12:42 -05001240 if security_groups_client is None:
1241 security_groups_client = self.security_groups_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001242 rules = []
1243 rulesets = [
1244 dict(
1245 # ssh
1246 protocol='tcp',
1247 port_range_min=22,
1248 port_range_max=22,
1249 ),
1250 dict(
1251 # ping
1252 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001253 ),
1254 dict(
1255 # ipv6-icmp for ping6
1256 protocol='icmp',
1257 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001258 )
1259 ]
John Warren456d9ae2016-01-12 15:36:33 -05001260 sec_group_rules_client = security_group_rules_client
Yair Fried1fc32a12014-08-04 09:11:30 +03001261 for ruleset in rulesets:
1262 for r_direction in ['ingress', 'egress']:
1263 ruleset['direction'] = r_direction
1264 try:
1265 sg_rule = self._create_security_group_rule(
John Warren456d9ae2016-01-12 15:36:33 -05001266 sec_group_rules_client=sec_group_rules_client,
1267 secgroup=secgroup,
John Warrenf9606e92015-12-10 12:12:42 -05001268 security_groups_client=security_groups_client,
1269 **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001270 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001271 # if rule already exist - skip rule and continue
1272 msg = 'Security group rule already exists'
1273 if msg not in ex._error_string:
1274 raise ex
1275 else:
Steve Heyman33735f22016-05-24 09:28:08 -05001276 self.assertEqual(r_direction, sg_rule['direction'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001277 rules.append(sg_rule)
1278
1279 return rules
1280
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001281 def _get_router(self, client=None, project_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001282 """Retrieve a router for the given tenant id.
1283
1284 If a public router has been configured, it will be returned.
1285
1286 If a public router has not been configured, but a public
1287 network has, a tenant router will be created and returned that
1288 routes traffic to the public network.
1289 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001290 if not client:
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001291 client = self.routers_client
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001292 if not project_id:
1293 project_id = client.project_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001294 router_id = CONF.network.public_router_id
1295 network_id = CONF.network.public_network_id
1296 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001297 body = client.show_router(router_id)
Steve Heyman33735f22016-05-24 09:28:08 -05001298 return body['router']
Yair Fried1fc32a12014-08-04 09:11:30 +03001299 elif network_id:
zhufl3484f992017-10-10 16:18:29 +08001300 router = client.create_router(
1301 name=data_utils.rand_name(self.__class__.__name__ + '-router'),
1302 admin_state_up=True,
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001303 project_id=project_id,
zhufl3484f992017-10-10 16:18:29 +08001304 external_gateway_info=dict(network_id=network_id))['router']
1305 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1306 client.delete_router, router['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001307 return router
1308 else:
1309 raise Exception("Neither of 'public_router_id' or "
1310 "'public_network_id' has been defined.")
1311
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001312 def create_networks(self, networks_client=None,
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001313 routers_client=None, subnets_client=None,
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001314 project_id=None, dns_nameservers=None,
Lajos Katonac87a06b2019-01-04 13:21:48 +01001315 port_security_enabled=True, **net_dict):
Yair Fried1fc32a12014-08-04 09:11:30 +03001316 """Create a network with a subnet connected to a router.
1317
David Shrewsbury9bac3662014-08-07 15:07:01 -04001318 The baremetal driver is a special case since all nodes are
1319 on the same shared network.
1320
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001321 :param project_id: id of project to create resources in.
Yair Fried413bf2d2014-11-19 17:07:11 +02001322 :param dns_nameservers: list of dns servers to send to subnet.
Lajos Katonac87a06b2019-01-04 13:21:48 +01001323 :param port_security_enabled: whether or not port_security is enabled
elajkate453fc22019-06-13 15:03:43 +02001324 :param net_dict: a dict containing experimental network information in
Lajos Katonac87a06b2019-01-04 13:21:48 +01001325 a form like this: {'provider:network_type': 'vlan',
1326 'provider:physical_network': 'foo',
1327 'provider:segmentation_id': '42'}
Yair Fried1fc32a12014-08-04 09:11:30 +03001328 :returns: network, subnet, router
1329 """
Thiago Paiva66cded22016-08-15 14:55:58 -03001330 if CONF.network.shared_physical_network:
David Shrewsbury9bac3662014-08-07 15:07:01 -04001331 # NOTE(Shrews): This exception is for environments where tenant
1332 # credential isolation is available, but network separation is
1333 # not (the current baremetal case). Likely can be removed when
1334 # test account mgmt is reworked:
1335 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001336 if not CONF.compute.fixed_network_name:
1337 m = 'fixed_network_name must be specified in config'
Matthew Treinish4217a702016-10-07 17:27:11 -04001338 raise lib_exc.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001339 network = self._get_network_by_name(
1340 CONF.compute.fixed_network_name)
1341 router = None
1342 subnet = None
1343 else:
John Warren94d8faf2015-09-15 12:22:24 -04001344 network = self._create_network(
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001345 networks_client=networks_client,
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001346 project_id=project_id,
Lajos Katonac87a06b2019-01-04 13:21:48 +01001347 port_security_enabled=port_security_enabled,
1348 **net_dict)
Ken'ichi Ohmichie35f4722015-12-22 04:57:11 +00001349 router = self._get_router(client=routers_client,
Rodolfo Alonso Hernandezc1449d42020-02-15 13:24:28 +00001350 project_id=project_id)
Ken'ichi Ohmichi43e7fcf2016-04-04 11:59:13 -07001351 subnet_kwargs = dict(network=network,
zhufl5b0a52f2017-10-24 15:48:20 +08001352 subnets_client=subnets_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001353 # use explicit check because empty list is a valid option
1354 if dns_nameservers is not None:
1355 subnet_kwargs['dns_nameservers'] = dns_nameservers
zhufl5b0a52f2017-10-24 15:48:20 +08001356 subnet = self.create_subnet(**subnet_kwargs)
Steve Heyman33735f22016-05-24 09:28:08 -05001357 if not routers_client:
1358 routers_client = self.routers_client
1359 router_id = router['id']
1360 routers_client.add_router_interface(router_id,
1361 subnet_id=subnet['id'])
1362
1363 # save a cleanup job to remove this association between
1364 # router and subnet
1365 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
1366 routers_client.remove_router_interface, router_id,
1367 subnet_id=subnet['id'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001368 return network, subnet, router
1369
1370
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001371class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001372 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001373
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001374 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001375
1376 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001377 def setup_clients(cls):
1378 super(EncryptionScenarioTest, cls).setup_clients()
ghanshyam6c682ff2018-08-06 09:54:45 +00001379 cls.admin_volume_types_client = cls.os_admin.volume_types_client_latest
ghanshyam3bd0d2b2017-03-23 01:57:28 +00001380 cls.admin_encryption_types_client =\
ghanshyam6c682ff2018-08-06 09:54:45 +00001381 cls.os_admin.encryption_types_client_latest
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001382
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001383 def create_encryption_type(self, client=None, type_id=None, provider=None,
1384 key_size=None, cipher=None,
1385 control_location=None):
1386 if not client:
Ken'ichi Ohmichia6ebf622016-08-25 11:52:27 -07001387 client = self.admin_encryption_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001388 if not type_id:
1389 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001390 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001391 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001392 client.create_encryption_type(
1393 type_id, provider=provider, key_size=key_size, cipher=cipher,
jeremy.zhangb6f67f62018-02-11 09:28:52 +08001394 control_location=control_location)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001395
lkuchlan3023e752017-06-08 12:53:13 +03001396 def create_encrypted_volume(self, encryption_provider, volume_type,
1397 key_size=256, cipher='aes-xts-plain64',
1398 control_location='front-end'):
1399 volume_type = self.create_volume_type(name=volume_type)
1400 self.create_encryption_type(type_id=volume_type['id'],
1401 provider=encryption_provider,
1402 key_size=key_size,
1403 cipher=cipher,
1404 control_location=control_location)
1405 return self.create_volume(volume_type=volume_type['name'])
1406
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001407
Masayuki Igawa0870db52015-09-18 21:08:36 +09001408class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001409 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001410
1411 Subclasses implement the tests that use the methods provided by this
1412 class.
1413 """
1414
1415 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001416 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001417 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001418 if not CONF.service_available.swift:
1419 skip_msg = ("%s skipped as swift is not available" %
1420 cls.__name__)
1421 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001422
1423 @classmethod
1424 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001425 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001426 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001427 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001428 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001429
1430 @classmethod
1431 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001432 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001433 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001434 cls.account_client = cls.os_operator.account_client
1435 cls.container_client = cls.os_operator.container_client
1436 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001437
Chris Dentde456a12014-09-10 12:41:15 +01001438 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001439 """get swift status for our user account."""
1440 self.account_client.list_account_containers()
1441 LOG.debug('Swift status information obtained successfully')
1442
Chris Dentde456a12014-09-10 12:41:15 +01001443 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001444 name = container_name or data_utils.rand_name(
1445 'swift-scenario-container')
ghanshyameed40312017-09-15 18:30:04 +03001446 self.container_client.update_container(name)
Chris Dent0d494112014-08-26 13:48:30 +01001447 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001448 self.list_and_check_container_objects(name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001449 LOG.debug('Container %s created', name)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001450 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001451 self.container_client.delete_container,
1452 name)
Chris Dent0d494112014-08-26 13:48:30 +01001453 return name
1454
Chris Dentde456a12014-09-10 12:41:15 +01001455 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001456 self.container_client.delete_container(container_name)
Jordan Pittier525ec712016-12-07 17:51:26 +01001457 LOG.debug('Container %s deleted', container_name)
Chris Dent0d494112014-08-26 13:48:30 +01001458
Chris Dentde456a12014-09-10 12:41:15 +01001459 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001460 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
Jordan Pittierb84f2d42016-12-21 19:02:15 +01001461 obj_data = data_utils.random_bytes()
Chris Dent0d494112014-08-26 13:48:30 +01001462 self.object_client.create_object(container_name, obj_name, obj_data)
Jordan Pittier9e227c52016-02-09 14:35:18 +01001463 self.addCleanup(test_utils.call_and_ignore_notfound_exc,
Chris Dent1d4313a2014-10-28 12:16:48 +00001464 self.object_client.delete_object,
1465 container_name,
1466 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001467 return obj_name, obj_data
1468
Chris Dentde456a12014-09-10 12:41:15 +01001469 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001470 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001471 self.list_and_check_container_objects(container_name,
1472 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001473
Chris Dentde456a12014-09-10 12:41:15 +01001474 def list_and_check_container_objects(self, container_name,
1475 present_obj=None,
1476 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001477 # List objects for a given container and assert which are present and
1478 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001479 if present_obj is None:
1480 present_obj = []
1481 if not_present_obj is None:
1482 not_present_obj = []
ghanshyam871b1a82017-09-14 02:56:16 +03001483 _, object_list = self.container_client.list_container_objects(
Chris Dent0d494112014-08-26 13:48:30 +01001484 container_name)
1485 if present_obj:
1486 for obj in present_obj:
1487 self.assertIn(obj, object_list)
1488 if not_present_obj:
1489 for obj in not_present_obj:
1490 self.assertNotIn(obj, object_list)
1491
Chris Dentde456a12014-09-10 12:41:15 +01001492 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001493 _, obj = self.object_client.get_object(container_name, obj_name)
1494 self.assertEqual(obj, expected_data)