blob: 5b092c31c2c0f0a98825209e09bdfe8e1c26d206 [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
Steve Bakerdd7c6ce2013-06-24 14:46:47 +120017import os
Sean Dague6dbc6da2013-05-08 17:49:46 -040018import subprocess
19
Sean Dague6dbc6da2013-05-08 17:49:46 -040020import netaddr
Matthew Treinish96e9e882014-06-09 18:37:19 -040021import six
Sean Dague6dbc6da2013-05-08 17:49:46 -040022
Andrea Frittoli422fbdf2014-03-20 10:05:18 +000023from tempest import auth
Andrea Frittolif9cde7e2014-02-18 09:57:04 +000024from tempest import clients
Andrea Frittoli8283b4e2014-07-17 13:28:58 +010025from tempest.common import credentials
Masayuki Igawa259c1132013-10-31 17:48:44 +090026from tempest.common.utils import data_utils
Masayuki Igawa4ded9f02014-02-17 15:05:59 +090027from tempest.common.utils.linux import remote_client
Matthew Treinish6c072292014-01-29 19:15:52 +000028from tempest import config
Giulio Fidente92f77192013-08-26 17:13:28 +020029from tempest import exceptions
Attila Fazekasfb7552a2013-08-27 13:02:26 +020030from tempest.openstack.common import log
Yair Fried1fc32a12014-08-04 09:11:30 +030031from tempest.services.network import resources as net_resources
Sean Dague6dbc6da2013-05-08 17:49:46 -040032import tempest.test
Sean Dague6dbc6da2013-05-08 17:49:46 -040033
Matthew Treinish6c072292014-01-29 19:15:52 +000034CONF = config.CONF
Sean Dague6dbc6da2013-05-08 17:49:46 -040035
Attila Fazekasfb7552a2013-08-27 13:02:26 +020036LOG = log.getLogger(__name__)
37
Sean Dague6dbc6da2013-05-08 17:49:46 -040038
Andrea Frittoli2e733b52014-07-16 14:12:11 +010039class ScenarioTest(tempest.test.BaseTestCase):
Andrea Frittoli486ede72014-09-25 11:50:05 +010040 """Base class for scenario tests. Uses tempest own clients. """
Andrea Frittoli2e733b52014-07-16 14:12:11 +010041
42 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +010043 def resource_setup(cls):
44 super(ScenarioTest, cls).resource_setup()
Andrea Frittoli8283b4e2014-07-17 13:28:58 +010045 # TODO(andreaf) Some of the code from this resource_setup could be
46 # moved into `BaseTestCase`
47 cls.isolated_creds = credentials.get_isolated_credentials(
Andrea Frittoliae9aca02014-09-25 11:43:11 +010048 cls.__name__, network_resources=cls.network_resources)
Andrea Frittoli2e733b52014-07-16 14:12:11 +010049 cls.manager = clients.Manager(
50 credentials=cls.credentials()
51 )
Andrea Frittoli247058f2014-07-16 16:09:22 +010052 cls.admin_manager = clients.Manager(cls.admin_credentials())
53 # Clients (in alphabetical order)
Adam Gandelmanc78c7572014-08-28 18:38:55 -070054 cls.flavors_client = cls.manager.flavors_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010055 cls.floating_ips_client = cls.manager.floating_ips_client
56 # Glance image client v1
57 cls.image_client = cls.manager.image_client
nithya-ganesan882595e2014-07-29 18:51:07 +000058 # Compute image client
59 cls.images_client = cls.manager.images_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010060 cls.keypairs_client = cls.manager.keypairs_client
61 cls.networks_client = cls.admin_manager.networks_client
62 # Nova security groups client
63 cls.security_groups_client = cls.manager.security_groups_client
64 cls.servers_client = cls.manager.servers_client
65 cls.volumes_client = cls.manager.volumes_client
Joseph Lanouxeef192f2014-08-01 14:32:53 +000066 cls.snapshots_client = cls.manager.snapshots_client
Yair Fried1fc32a12014-08-04 09:11:30 +030067 cls.interface_client = cls.manager.interfaces_client
68 # Neutron network client
69 cls.network_client = cls.manager.network_client
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090070 # Heat client
71 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010072
73 @classmethod
Andrea Frittoli2e733b52014-07-16 14:12:11 +010074 def credentials(cls):
Andrea Frittoli8283b4e2014-07-17 13:28:58 +010075 return cls.isolated_creds.get_primary_creds()
Andrea Frittoli2e733b52014-07-16 14:12:11 +010076
Masayuki Igawaccd66592014-07-17 00:42:42 +090077 @classmethod
Yair Frieddb6c9e92014-08-06 08:53:13 +030078 def alt_credentials(cls):
Andrea Frittoli8283b4e2014-07-17 13:28:58 +010079 return cls.isolated_creds.get_alt_creds()
Yair Frieddb6c9e92014-08-06 08:53:13 +030080
81 @classmethod
Masayuki Igawaccd66592014-07-17 00:42:42 +090082 def admin_credentials(cls):
Andrea Frittoli8283b4e2014-07-17 13:28:58 +010083 try:
84 return cls.isolated_creds.get_admin_creds()
85 except NotImplementedError:
86 raise cls.skipException('Admin Credentials are not available')
Masayuki Igawaccd66592014-07-17 00:42:42 +090087
Andrea Frittoli247058f2014-07-16 16:09:22 +010088 # ## Methods to handle sync and async deletes
89
90 def setUp(self):
91 super(ScenarioTest, self).setUp()
92 self.cleanup_waits = []
93 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
94 # because scenario tests in the same test class should not share
95 # resources. If resources were shared between test cases then it
96 # should be a single scenario test instead of multiples.
97
98 # NOTE(yfried): this list is cleaned at the end of test_methods and
99 # not at the end of the class
100 self.addCleanup(self._wait_for_cleanups)
101
Yair Fried1fc32a12014-08-04 09:11:30 +0300102 def delete_wrapper(self, delete_thing, *args, **kwargs):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100103 """Ignores NotFound exceptions for delete operations.
104
Yair Fried1fc32a12014-08-04 09:11:30 +0300105 @param delete_thing: delete method of a resource. method will be
106 executed as delete_thing(*args, **kwargs)
107
Andrea Frittoli247058f2014-07-16 16:09:22 +0100108 """
109 try:
110 # Tempest clients return dicts, so there is no common delete
111 # method available. Using a callable instead
Yair Fried1fc32a12014-08-04 09:11:30 +0300112 delete_thing(*args, **kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100113 except exceptions.NotFound:
114 # If the resource is already missing, mission accomplished.
115 pass
116
117 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +0900118 cleanup_callable, cleanup_args=None,
119 cleanup_kwargs=None, ignore_error=True):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700120 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100121
122 @param waiter_callable: callable to wait for the resource to delete
123 @param thing_id: the id of the resource to be cleaned-up
124 @param thing_id_param: the name of the id param in the waiter
125 @param cleanup_callable: method to load pass to self.addCleanup with
126 the following *cleanup_args, **cleanup_kwargs.
127 usually a delete method.
128 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900129 if cleanup_args is None:
130 cleanup_args = []
131 if cleanup_kwargs is None:
132 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100133 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
134 wait_dict = {
135 'waiter_callable': waiter_callable,
136 thing_id_param: thing_id
137 }
138 self.cleanup_waits.append(wait_dict)
139
140 def _wait_for_cleanups(self):
141 """To handle async delete actions, a list of waits is added
142 which will be iterated over as the last step of clearing the
143 cleanup queue. That way all the delete calls are made up front
144 and the tests won't succeed unless the deletes are eventually
145 successful. This is the same basic approach used in the api tests to
146 limit cleanup execution time except here it is multi-resource,
147 because of the nature of the scenario tests.
148 """
149 for wait in self.cleanup_waits:
150 waiter_callable = wait.pop('waiter_callable')
151 waiter_callable(**wait)
152
153 # ## Test functions library
154 #
155 # The create_[resource] functions only return body and discard the
156 # resp part which is not used in scenario tests
157
Yair Frieddb6c9e92014-08-06 08:53:13 +0300158 def create_keypair(self, client=None):
159 if not client:
160 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100161 name = data_utils.rand_name(self.__class__.__name__)
162 # We don't need to create a keypair by pubkey in scenario
Yair Frieddb6c9e92014-08-06 08:53:13 +0300163 resp, body = client.create_keypair(name)
164 self.addCleanup(client.delete_keypair, name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100165 return body
166
167 def create_server(self, name=None, image=None, flavor=None,
168 wait_on_boot=True, wait_on_delete=True,
Ghanshyam2a180b82014-06-16 13:54:22 +0900169 create_kwargs=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100170 """Creates VM instance.
171
172 @param image: image from which to create the instance
173 @param wait_on_boot: wait for status ACTIVE before continue
174 @param wait_on_delete: force synchronous delete on cleanup
175 @param create_kwargs: additional details for instance creation
176 @return: server dict
177 """
178 if name is None:
179 name = data_utils.rand_name(self.__class__.__name__)
180 if image is None:
181 image = CONF.compute.image_ref
182 if flavor is None:
183 flavor = CONF.compute.flavor_ref
Ghanshyam2a180b82014-06-16 13:54:22 +0900184 if create_kwargs is None:
185 create_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100186
Andrea Frittoli247058f2014-07-16 16:09:22 +0100187 LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
188 name, image, flavor)
189 _, server = self.servers_client.create_server(name, image, flavor,
190 **create_kwargs)
191 if wait_on_delete:
192 self.addCleanup(self.servers_client.wait_for_server_termination,
193 server['id'])
194 self.addCleanup_with_wait(
195 waiter_callable=self.servers_client.wait_for_server_termination,
196 thing_id=server['id'], thing_id_param='server_id',
197 cleanup_callable=self.delete_wrapper,
198 cleanup_args=[self.servers_client.delete_server, server['id']])
199 if wait_on_boot:
200 self.servers_client.wait_for_server_status(server_id=server['id'],
201 status='ACTIVE')
202 # The instance retrieved on creation is missing network
203 # details, necessitating retrieval after it becomes active to
204 # ensure correct details.
205 _, server = self.servers_client.get_server(server['id'])
206 self.assertEqual(server['name'], name)
207 return server
208
209 def create_volume(self, size=1, name=None, snapshot_id=None,
210 imageRef=None, volume_type=None, wait_on_delete=True):
211 if name is None:
212 name = data_utils.rand_name(self.__class__.__name__)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000213 volume = self.volumes_client.create_volume(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100214 size=size, display_name=name, snapshot_id=snapshot_id,
215 imageRef=imageRef, volume_type=volume_type)
Matt Riedemanne85c2702014-09-10 11:50:13 -0700216
Andrea Frittoli247058f2014-07-16 16:09:22 +0100217 if wait_on_delete:
218 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
219 volume['id'])
Matt Riedemanne85c2702014-09-10 11:50:13 -0700220 self.addCleanup(self.delete_wrapper,
221 self.volumes_client.delete_volume, volume['id'])
222 else:
223 self.addCleanup_with_wait(
224 waiter_callable=self.volumes_client.wait_for_resource_deletion,
225 thing_id=volume['id'], thing_id_param='id',
226 cleanup_callable=self.delete_wrapper,
227 cleanup_args=[self.volumes_client.delete_volume, volume['id']])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100228
229 self.assertEqual(name, volume['display_name'])
230 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
231 # The volume retrieved on creation has a non-up-to-date status.
232 # Retrieval after it becomes active ensures correct details.
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000233 volume = self.volumes_client.get_volume(volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100234 return volume
235
Yair Fried1fc32a12014-08-04 09:11:30 +0300236 def _create_loginable_secgroup_rule(self, secgroup_id=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100237 _client = self.security_groups_client
238 if secgroup_id is None:
239 _, sgs = _client.list_security_groups()
240 for sg in sgs:
241 if sg['name'] == 'default':
242 secgroup_id = sg['id']
243
244 # These rules are intended to permit inbound ssh and icmp
245 # traffic from all sources, so no group_id is provided.
246 # Setting a group_id would only permit traffic from ports
247 # belonging to the same security group.
248 rulesets = [
249 {
250 # ssh
251 'ip_proto': 'tcp',
252 'from_port': 22,
253 'to_port': 22,
254 'cidr': '0.0.0.0/0',
255 },
256 {
257 # ping
258 'ip_proto': 'icmp',
259 'from_port': -1,
260 'to_port': -1,
261 'cidr': '0.0.0.0/0',
262 }
263 ]
264 rules = list()
265 for ruleset in rulesets:
266 _, sg_rule = _client.create_security_group_rule(secgroup_id,
267 **ruleset)
268 self.addCleanup(self.delete_wrapper,
269 _client.delete_security_group_rule,
270 sg_rule['id'])
271 rules.append(sg_rule)
272 return rules
273
Yair Fried1fc32a12014-08-04 09:11:30 +0300274 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100275 # Create security group
276 sg_name = data_utils.rand_name(self.__class__.__name__)
277 sg_desc = sg_name + " description"
278 _, secgroup = self.security_groups_client.create_security_group(
279 sg_name, sg_desc)
280 self.assertEqual(secgroup['name'], sg_name)
281 self.assertEqual(secgroup['description'], sg_desc)
282 self.addCleanup(self.delete_wrapper,
283 self.security_groups_client.delete_security_group,
284 secgroup['id'])
285
286 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300287 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100288
289 return secgroup
290
JordanP3fe2dc32014-11-17 13:06:01 +0100291 def get_remote_client(self, server_or_ip, username=None, private_key=None,
292 log_console_of_servers=None):
293 """Get a SSH client to a remote server
294
295 @param server_or_ip a server object as returned by Tempest compute
296 client or an IP address to connect to
297 @param username name of the Linux account on the remote server
298 @param private_key the SSH private key to use
299 @param log_console_of_servers a list of server objects. Each server
300 in the list will have its console printed in the logs in case the
301 SSH connection failed to be established
302 @return a RemoteClient object
303 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100304 if isinstance(server_or_ip, six.string_types):
305 ip = server_or_ip
306 else:
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700307 addr = server_or_ip['addresses'][CONF.compute.network_for_ssh][0]
308 ip = addr['addr']
309
Andrea Frittoli247058f2014-07-16 16:09:22 +0100310 if username is None:
311 username = CONF.scenario.ssh_user
312 if private_key is None:
313 private_key = self.keypair['private_key']
314 linux_client = remote_client.RemoteClient(ip, username,
315 pkey=private_key)
316 try:
317 linux_client.validate_authentication()
JordanP3fe2dc32014-11-17 13:06:01 +0100318 except Exception:
319 LOG.exception('Initializing SSH connection to %s failed' % ip)
JordanP3fe2dc32014-11-17 13:06:01 +0100320 # If we don't explicitely set for which servers we want to
321 # log the console output then all the servers will be logged.
322 # See the definition of _log_console_output()
323 self._log_console_output(log_console_of_servers)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100324 raise
325
326 return linux_client
327
Ghanshyam2a180b82014-06-16 13:54:22 +0900328 def _image_create(self, name, fmt, path, properties=None):
329 if properties is None:
330 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100331 name = data_utils.rand_name('%s-' % name)
332 image_file = open(path, 'rb')
333 self.addCleanup(image_file.close)
334 params = {
335 'name': name,
336 'container_format': fmt,
337 'disk_format': fmt,
338 'is_public': 'False',
339 }
340 params.update(properties)
David Kranz34f18782015-01-06 13:43:55 -0500341 image = self.image_client.create_image(**params)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100342 self.addCleanup(self.image_client.delete_image, image['id'])
343 self.assertEqual("queued", image['status'])
344 self.image_client.update_image(image['id'], data=image_file)
345 return image['id']
346
347 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300348 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100349 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
350 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
351 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300352 img_container_format = CONF.scenario.img_container_format
353 img_disk_format = CONF.scenario.img_disk_format
354 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
355 "ami: %s, ari: %s, aki: %s" %
356 (img_path, img_container_format, img_disk_format,
357 ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100358 try:
359 self.image = self._image_create('scenario-img',
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300360 img_container_format,
361 img_path,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100362 properties={'disk_format':
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300363 img_disk_format})
Andrea Frittoli247058f2014-07-16 16:09:22 +0100364 except IOError:
365 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
366 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
367 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
368 properties = {
369 'properties': {'kernel_id': kernel, 'ramdisk_id': ramdisk}
370 }
371 self.image = self._image_create('scenario-ami', 'ami',
372 path=ami_img_path,
373 properties=properties)
374 LOG.debug("image:%s" % self.image)
375
376 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400377 if not CONF.compute_feature_enabled.console_output:
378 LOG.debug('Console output not supported, cannot log')
379 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100380 if not servers:
381 _, servers = self.servers_client.list_servers()
382 servers = servers['servers']
383 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500384 console_output = self.servers_client.get_console_output(
385 server['id'], length=None)
386 LOG.debug('Console output for %s\nhead=%s\nbody=\n%s',
387 server['id'], console_output[0], console_output[1])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100388
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000389 def _log_net_info(self, exc):
390 # network debug is called as part of ssh init
391 if not isinstance(exc, exceptions.SSHTimeout):
392 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000393
nithya-ganesan882595e2014-07-29 18:51:07 +0000394 def create_server_snapshot(self, server, name=None):
395 # Glance client
396 _image_client = self.image_client
397 # Compute client
398 _images_client = self.images_client
399 if name is None:
400 name = data_utils.rand_name('scenario-snapshot-')
401 LOG.debug("Creating a snapshot image for server: %s", server['name'])
David Kranza5299eb2015-01-15 17:24:05 -0500402 image = _images_client.create_image(server['id'], name)
403 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000404 _image_client.wait_for_image_status(image_id, 'active')
405 self.addCleanup_with_wait(
406 waiter_callable=_image_client.wait_for_resource_deletion,
407 thing_id=image_id, thing_id_param='id',
408 cleanup_callable=self.delete_wrapper,
409 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500410 snapshot_image = _image_client.get_image_meta(image_id)
nithya-ganesan882595e2014-07-29 18:51:07 +0000411 image_name = snapshot_image['name']
412 self.assertEqual(name, image_name)
413 LOG.debug("Created snapshot image %s for server %s",
414 image_name, server['name'])
415 return snapshot_image
416
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900417 def nova_volume_attach(self):
418 # TODO(andreaf) Device should be here CONF.compute.volume_device_name
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000419 volume = self.servers_client.attach_volume(
420 self.server['id'], self.volume['id'], '/dev/vdb')[1]
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900421 self.assertEqual(self.volume['id'], volume['id'])
422 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
423 # Refresh the volume after the attachment
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000424 self.volume = self.volumes_client.get_volume(volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900425
426 def nova_volume_detach(self):
427 self.servers_client.detach_volume(self.server['id'], self.volume['id'])
428 self.volumes_client.wait_for_volume_status(self.volume['id'],
429 'available')
430
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000431 volume = self.volumes_client.get_volume(self.volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900432 self.assertEqual('available', volume['status'])
433
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700434 def rebuild_server(self, server_id, image=None,
435 preserve_ephemeral=False, wait=True,
436 rebuild_kwargs=None):
437 if image is None:
438 image = CONF.compute.image_ref
439
440 rebuild_kwargs = rebuild_kwargs or {}
441
442 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
443 server_id, image, preserve_ephemeral)
444 self.servers_client.rebuild(server_id=server_id, image_ref=image,
445 preserve_ephemeral=preserve_ephemeral,
446 **rebuild_kwargs)
447 if wait:
448 self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
449
Steven Hardyda2a8352014-10-02 12:52:20 +0100450 def ping_ip_address(self, ip_address, should_succeed=True,
451 ping_timeout=None):
452 timeout = ping_timeout or CONF.compute.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700453 cmd = ['ping', '-c1', '-w1', ip_address]
454
455 def ping():
456 proc = subprocess.Popen(cmd,
457 stdout=subprocess.PIPE,
458 stderr=subprocess.PIPE)
459 proc.communicate()
460 return (proc.returncode == 0) == should_succeed
461
Steven Hardyda2a8352014-10-02 12:52:20 +0100462 return tempest.test.call_until_true(ping, timeout, 1)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700463
Yair Friedae0e73d2014-11-24 11:56:26 +0200464 def check_vm_connectivity(self, ip_address,
465 username=None,
466 private_key=None,
467 should_connect=True):
468 """
469 :param ip_address: server to test against
470 :param username: server's ssh username
471 :param private_key: server's ssh private key to be used
472 :param should_connect: True/False indicates positive/negative test
473 positive - attempt ping and ssh
474 negative - attempt ping and fail if succeed
475
476 :raises: AssertError if the result of the connectivity check does
477 not match the value of the should_connect param
478 """
479 if should_connect:
480 msg = "Timed out waiting for %s to become reachable" % ip_address
481 else:
482 msg = "ip address %s is reachable" % ip_address
483 self.assertTrue(self.ping_ip_address(ip_address,
484 should_succeed=should_connect),
485 msg=msg)
486 if should_connect:
487 # no need to check ssh for negative connectivity
488 self.get_remote_client(ip_address, username, private_key)
489
490 def check_public_network_connectivity(self, ip_address, username,
491 private_key, should_connect=True,
492 msg=None, servers=None):
493 # The target login is assumed to have been configured for
494 # key-based authentication by cloud-init.
495 LOG.debug('checking network connections to IP %s with user: %s' %
496 (ip_address, username))
497 try:
498 self.check_vm_connectivity(ip_address,
499 username,
500 private_key,
501 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500502 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200503 ex_msg = 'Public network connectivity check failed'
504 if msg:
505 ex_msg += ": " + msg
506 LOG.exception(ex_msg)
507 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200508 raise
509
510 def create_floating_ip(self, thing, pool_name=None):
511 """Creates a floating IP and associates to a server using
512 Nova clients
513 """
514
515 _, floating_ip = self.floating_ips_client.create_floating_ip(pool_name)
516 self.addCleanup(self.delete_wrapper,
517 self.floating_ips_client.delete_floating_ip,
518 floating_ip['id'])
519 self.floating_ips_client.associate_floating_ip_to_server(
520 floating_ip['ip'], thing['id'])
521 return floating_ip
522
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100523
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100524class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300525 """Base class for network scenario tests.
526 This class provide helpers for network scenario tests, using the neutron
527 API. Helpers from ancestor which use the nova network API are overridden
528 with the neutron API.
529
530 This Class also enforces using Neutron instead of novanetwork.
531 Subclassed tests will be skipped if Neutron is not enabled
532
533 """
534
535 @classmethod
536 def check_preconditions(cls):
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100537 if not CONF.service_available.neutron:
538 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300539
540 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100541 def resource_setup(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +0900542 cls.check_preconditions()
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100543 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300544 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300545
Yair Frieddb6c9e92014-08-06 08:53:13 +0300546 def _create_network(self, client=None, tenant_id=None,
547 namestart='network-smoke-'):
548 if not client:
549 client = self.network_client
550 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000551 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300552 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500553 result = client.create_network(name=name, tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300554 network = net_resources.DeletableNetwork(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300555 **result['network'])
556 self.assertEqual(network.name, name)
557 self.addCleanup(self.delete_wrapper, network.delete)
558 return network
559
560 def _list_networks(self, *args, **kwargs):
561 """List networks using admin creds """
562 return self._admin_lister('networks')(*args, **kwargs)
563
564 def _list_subnets(self, *args, **kwargs):
565 """List subnets using admin creds """
566 return self._admin_lister('subnets')(*args, **kwargs)
567
568 def _list_routers(self, *args, **kwargs):
569 """List routers using admin creds """
570 return self._admin_lister('routers')(*args, **kwargs)
571
572 def _list_ports(self, *args, **kwargs):
573 """List ports using admin creds """
574 return self._admin_lister('ports')(*args, **kwargs)
575
576 def _admin_lister(self, resource_type):
577 def temp(*args, **kwargs):
578 temp_method = self.admin_manager.network_client.__getattr__(
579 'list_%s' % resource_type)
David Kranz34e88122014-12-11 15:24:05 -0500580 resource_list = temp_method(*args, **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300581 return resource_list[resource_type]
582 return temp
583
Yair Frieddb6c9e92014-08-06 08:53:13 +0300584 def _create_subnet(self, network, client=None, namestart='subnet-smoke',
585 **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300586 """
587 Create a subnet for the given network within the cidr block
588 configured for tenant networks.
589 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300590 if not client:
591 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300592
593 def cidr_in_use(cidr, tenant_id):
594 """
595 :return True if subnet with cidr already exist in tenant
596 False else
597 """
598 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
599 return len(cidr_in_use) != 0
600
Kirill Shileev14113572014-11-21 16:58:02 +0300601 ip_version = kwargs.pop('ip_version', 4)
602
603 if ip_version == 6:
604 tenant_cidr = netaddr.IPNetwork(
605 CONF.network.tenant_network_v6_cidr)
606 num_bits = CONF.network.tenant_network_v6_mask_bits
607 else:
608 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
609 num_bits = CONF.network.tenant_network_mask_bits
610
Yair Fried1fc32a12014-08-04 09:11:30 +0300611 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300612 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300613 # Repeatedly attempt subnet creation with sequential cidr
614 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300615 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300616 str_cidr = str(subnet_cidr)
617 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
618 continue
619
620 subnet = dict(
621 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300622 network_id=network.id,
623 tenant_id=network.tenant_id,
624 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300625 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300626 **kwargs
627 )
628 try:
David Kranz34e88122014-12-11 15:24:05 -0500629 result = client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300630 break
Yair Frieddb6c9e92014-08-06 08:53:13 +0300631 except exceptions.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300632 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
633 if not is_overlapping_cidr:
634 raise
635 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300636 subnet = net_resources.DeletableSubnet(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300637 **result['subnet'])
638 self.assertEqual(subnet.cidr, str_cidr)
639 self.addCleanup(self.delete_wrapper, subnet.delete)
640 return subnet
641
Yair Frieddb6c9e92014-08-06 08:53:13 +0300642 def _create_port(self, network, client=None, namestart='port-quotatest'):
643 if not client:
644 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300645 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500646 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300647 name=name,
648 network_id=network.id,
649 tenant_id=network.tenant_id)
650 self.assertIsNotNone(result, 'Unable to allocate port')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300651 port = net_resources.DeletablePort(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300652 **result['port'])
653 self.addCleanup(self.delete_wrapper, port.delete)
654 return port
655
Kirill Shileev14113572014-11-21 16:58:02 +0300656 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300657 ports = self._list_ports(device_id=server['id'],
658 fixed_ip=ip_addr)
659 self.assertEqual(len(ports), 1,
660 "Unable to determine which port to target.")
Kirill Shileev14113572014-11-21 16:58:02 +0300661 # it might happen here that this port has more then one ip address
662 # as in case of dual stack- when this port is created on 2 subnets
663 for ip46 in ports[0]['fixed_ips']:
664 ip = ip46['ip_address']
665 if netaddr.valid_ipv4(ip):
666 return ports[0]['id'], ip
Yair Fried1fc32a12014-08-04 09:11:30 +0300667
David Shrewsbury9bac3662014-08-07 15:07:01 -0400668 def _get_network_by_name(self, network_name):
669 net = self._list_networks(name=network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300670 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400671
Yair Friedae0e73d2014-11-24 11:56:26 +0200672 def create_floating_ip(self, thing, external_network_id=None,
673 port_id=None, client=None):
674 """Creates a floating IP and associates to a resource/port using
675 Neutron client
676 """
677 if not external_network_id:
678 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300679 if not client:
680 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300681 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300682 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
683 else:
684 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500685 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300686 floating_network_id=external_network_id,
687 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300688 tenant_id=thing['tenant_id'],
689 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300690 )
691 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300692 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300693 **result['floatingip'])
694 self.addCleanup(self.delete_wrapper, floating_ip.delete)
695 return floating_ip
696
697 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300698 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300699 floating_ip.update(port_id=port_id)
700 self.assertEqual(port_id, floating_ip.port_id)
701 return floating_ip
702
703 def _disassociate_floating_ip(self, floating_ip):
704 """
705 :param floating_ip: type DeletableFloatingIp
706 """
707 floating_ip.update(port_id=None)
708 self.assertIsNone(floating_ip.port_id)
709 return floating_ip
710
Yair Fried45f92952014-06-26 05:19:19 +0300711 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000712 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300713
714 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
715 to check status
716 :param status: target status
717 :raises: AssertionError if status doesn't match
718 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000719 def refresh():
720 floating_ip.refresh()
721 return status == floating_ip.status
722
723 tempest.test.call_until_true(refresh,
724 CONF.network.build_timeout,
725 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300726 self.assertEqual(status, floating_ip.status,
727 message="FloatingIP: {fp} is at status: {cst}. "
728 "failed to reach status: {st}"
729 .format(fp=floating_ip, cst=floating_ip.status,
730 st=status))
731 LOG.info("FloatingIP: {fp} is at status: {st}"
732 .format(fp=floating_ip, st=status))
733
Yair Fried1fc32a12014-08-04 09:11:30 +0300734 def _check_tenant_network_connectivity(self, server,
735 username,
736 private_key,
737 should_connect=True,
738 servers_for_debug=None):
739 if not CONF.network.tenant_networks_reachable:
740 msg = 'Tenant networks not configured to be reachable.'
741 LOG.info(msg)
742 return
743 # The target login is assumed to have been configured for
744 # key-based authentication by cloud-init.
745 try:
ghanshyam807211c2014-12-18 13:21:22 +0900746 for net_name, ip_addresses in server['addresses'].iteritems():
Yair Fried1fc32a12014-08-04 09:11:30 +0300747 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900748 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200749 username,
750 private_key,
751 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300752 except Exception as e:
753 LOG.exception('Tenant network connectivity check failed')
754 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000755 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300756 raise
757
758 def _check_remote_connectivity(self, source, dest, should_succeed=True):
759 """
760 check ping server via source ssh connection
761
762 :param source: RemoteClient: an ssh connection from which to ping
763 :param dest: and IP to ping against
764 :param should_succeed: boolean should ping succeed or not
765 :returns: boolean -- should_succeed == ping
766 :returns: ping is false if ping failed
767 """
768 def ping_remote():
769 try:
770 source.ping_host(dest)
771 except exceptions.SSHExecCommandFailed:
772 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
773 % (dest, source.ssh_client.host))
774 return not should_succeed
775 return should_succeed
776
777 return tempest.test.call_until_true(ping_remote,
778 CONF.compute.ping_timeout,
779 1)
780
Yair Frieddb6c9e92014-08-06 08:53:13 +0300781 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300782 namestart='secgroup-smoke'):
783 if client is None:
784 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300785 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000786 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300787 secgroup = self._create_empty_security_group(namestart=namestart,
788 client=client,
789 tenant_id=tenant_id)
790
791 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900792 rules = self._create_loginable_secgroup_rule(client=client,
793 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300794 for rule in rules:
795 self.assertEqual(tenant_id, rule.tenant_id)
796 self.assertEqual(secgroup.id, rule.security_group_id)
797 return secgroup
798
Yair Frieddb6c9e92014-08-06 08:53:13 +0300799 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300800 namestart='secgroup-smoke'):
801 """Create a security group without rules.
802
803 Default rules will be created:
804 - IPv4 egress to any
805 - IPv6 egress to any
806
807 :param tenant_id: secgroup will be created in this tenant
808 :returns: DeletableSecurityGroup -- containing the secgroup created
809 """
810 if client is None:
811 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300812 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000813 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300814 sg_name = data_utils.rand_name(namestart)
815 sg_desc = sg_name + " description"
816 sg_dict = dict(name=sg_name,
817 description=sg_desc)
818 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500819 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300820 secgroup = net_resources.DeletableSecurityGroup(
821 client=client,
822 **result['security_group']
823 )
824 self.assertEqual(secgroup.name, sg_name)
825 self.assertEqual(tenant_id, secgroup.tenant_id)
826 self.assertEqual(secgroup.description, sg_desc)
827 self.addCleanup(self.delete_wrapper, secgroup.delete)
828 return secgroup
829
Yair Frieddb6c9e92014-08-06 08:53:13 +0300830 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300831 """Get default secgroup for given tenant_id.
832
833 :returns: DeletableSecurityGroup -- default secgroup for given tenant
834 """
835 if client is None:
836 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300837 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000838 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300839 sgs = [
840 sg for sg in client.list_security_groups().values()[0]
841 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
842 ]
843 msg = "No default security group for tenant %s." % (tenant_id)
844 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300845 return net_resources.DeletableSecurityGroup(client=client,
846 **sgs[0])
847
Yair Frieddb6c9e92014-08-06 08:53:13 +0300848 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300849 tenant_id=None, **kwargs):
850 """Create a rule from a dictionary of rule parameters.
851
852 Create a rule in a secgroup. if secgroup not defined will search for
853 default secgroup in tenant_id.
854
855 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300856 :param tenant_id: if secgroup not passed -- the tenant in which to
857 search for default secgroup
858 :param kwargs: a dictionary containing rule parameters:
859 for example, to allow incoming ssh:
860 rule = {
861 direction: 'ingress'
862 protocol:'tcp',
863 port_range_min: 22,
864 port_range_max: 22
865 }
866 """
867 if client is None:
868 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300869 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000870 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300871 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300872 secgroup = self._default_security_group(client=client,
873 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300874
875 ruleset = dict(security_group_id=secgroup.id,
876 tenant_id=secgroup.tenant_id)
877 ruleset.update(kwargs)
878
David Kranz34e88122014-12-11 15:24:05 -0500879 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300880 sg_rule = net_resources.DeletableSecurityGroupRule(
881 client=client,
882 **sg_rule['security_group_rule']
883 )
884 self.addCleanup(self.delete_wrapper, sg_rule.delete)
885 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
886 self.assertEqual(secgroup.id, sg_rule.security_group_id)
887
888 return sg_rule
889
890 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
891 """These rules are intended to permit inbound ssh and icmp
892 traffic from all sources, so no group_id is provided.
893 Setting a group_id would only permit traffic from ports
894 belonging to the same security group.
895 """
896
897 if client is None:
898 client = self.network_client
899 rules = []
900 rulesets = [
901 dict(
902 # ssh
903 protocol='tcp',
904 port_range_min=22,
905 port_range_max=22,
906 ),
907 dict(
908 # ping
909 protocol='icmp',
910 )
911 ]
912 for ruleset in rulesets:
913 for r_direction in ['ingress', 'egress']:
914 ruleset['direction'] = r_direction
915 try:
916 sg_rule = self._create_security_group_rule(
917 client=client, secgroup=secgroup, **ruleset)
918 except exceptions.Conflict as ex:
919 # if rule already exist - skip rule and continue
920 msg = 'Security group rule already exists'
921 if msg not in ex._error_string:
922 raise ex
923 else:
924 self.assertEqual(r_direction, sg_rule.direction)
925 rules.append(sg_rule)
926
927 return rules
928
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500929 def _create_pool(self, lb_method, protocol, subnet_id):
930 """Wrapper utility that returns a test pool."""
931 client = self.network_client
932 name = data_utils.rand_name('pool')
David Kranz34e88122014-12-11 15:24:05 -0500933 resp_pool = client.create_pool(protocol=protocol, name=name,
934 subnet_id=subnet_id,
935 lb_method=lb_method)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500936 pool = net_resources.DeletablePool(client=client, **resp_pool['pool'])
937 self.assertEqual(pool['name'], name)
938 self.addCleanup(self.delete_wrapper, pool.delete)
939 return pool
940
941 def _create_member(self, address, protocol_port, pool_id):
942 """Wrapper utility that returns a test member."""
943 client = self.network_client
David Kranz34e88122014-12-11 15:24:05 -0500944 resp_member = client.create_member(protocol_port=protocol_port,
945 pool_id=pool_id,
946 address=address)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500947 member = net_resources.DeletableMember(client=client,
948 **resp_member['member'])
949 self.addCleanup(self.delete_wrapper, member.delete)
950 return member
951
952 def _create_vip(self, protocol, protocol_port, subnet_id, pool_id):
953 """Wrapper utility that returns a test vip."""
954 client = self.network_client
955 name = data_utils.rand_name('vip')
David Kranz34e88122014-12-11 15:24:05 -0500956 resp_vip = client.create_vip(protocol=protocol, name=name,
957 subnet_id=subnet_id, pool_id=pool_id,
958 protocol_port=protocol_port)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500959 vip = net_resources.DeletableVip(client=client, **resp_vip['vip'])
960 self.assertEqual(vip['name'], name)
961 self.addCleanup(self.delete_wrapper, vip.delete)
962 return vip
963
Yair Fried1fc32a12014-08-04 09:11:30 +0300964 def _ssh_to_server(self, server, private_key):
965 ssh_login = CONF.compute.image_ssh_user
966 return self.get_remote_client(server,
967 username=ssh_login,
968 private_key=private_key)
969
Yair Frieddb6c9e92014-08-06 08:53:13 +0300970 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300971 """Retrieve a router for the given tenant id.
972
973 If a public router has been configured, it will be returned.
974
975 If a public router has not been configured, but a public
976 network has, a tenant router will be created and returned that
977 routes traffic to the public network.
978 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300979 if not client:
980 client = self.network_client
981 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000982 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300983 router_id = CONF.network.public_router_id
984 network_id = CONF.network.public_network_id
985 if router_id:
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +0400986 resp, body = client.show_router(router_id)
987 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300988 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300989 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300990 router.set_gateway(network_id)
991 return router
992 else:
993 raise Exception("Neither of 'public_router_id' or "
994 "'public_network_id' has been defined.")
995
Yair Frieddb6c9e92014-08-06 08:53:13 +0300996 def _create_router(self, client=None, tenant_id=None,
997 namestart='router-smoke'):
998 if not client:
999 client = self.network_client
1000 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001001 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001002 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001003 result = client.create_router(name=name,
1004 admin_state_up=True,
1005 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001006 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001007 **result['router'])
1008 self.assertEqual(router.name, name)
1009 self.addCleanup(self.delete_wrapper, router.delete)
1010 return router
1011
Alok Maurya6384bbb2014-07-13 06:44:29 -07001012 def _update_router_admin_state(self, router, admin_state_up):
1013 router.update(admin_state_up=admin_state_up)
1014 self.assertEqual(admin_state_up, router.admin_state_up)
1015
Yair Fried413bf2d2014-11-19 17:07:11 +02001016 def create_networks(self, client=None, tenant_id=None,
1017 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001018 """Create a network with a subnet connected to a router.
1019
David Shrewsbury9bac3662014-08-07 15:07:01 -04001020 The baremetal driver is a special case since all nodes are
1021 on the same shared network.
1022
Yair Fried413bf2d2014-11-19 17:07:11 +02001023 :param client: network client to create resources with.
1024 :param tenant_id: id of tenant to create resources in.
1025 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001026 :returns: network, subnet, router
1027 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001028 if CONF.baremetal.driver_enabled:
1029 # NOTE(Shrews): This exception is for environments where tenant
1030 # credential isolation is available, but network separation is
1031 # not (the current baremetal case). Likely can be removed when
1032 # test account mgmt is reworked:
1033 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
1034 network = self._get_network_by_name(
1035 CONF.compute.fixed_network_name)
1036 router = None
1037 subnet = None
1038 else:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001039 network = self._create_network(client=client, tenant_id=tenant_id)
1040 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001041
1042 subnet_kwargs = dict(network=network, client=client)
1043 # use explicit check because empty list is a valid option
1044 if dns_nameservers is not None:
1045 subnet_kwargs['dns_nameservers'] = dns_nameservers
1046 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001047 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001048 return network, subnet, router
1049
1050
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001051# power/provision states as of icehouse
1052class BaremetalPowerStates(object):
1053 """Possible power states of an Ironic node."""
1054 POWER_ON = 'power on'
1055 POWER_OFF = 'power off'
1056 REBOOT = 'rebooting'
1057 SUSPEND = 'suspended'
1058
1059
1060class BaremetalProvisionStates(object):
1061 """Possible provision states of an Ironic node."""
1062 NOSTATE = None
1063 INIT = 'initializing'
1064 ACTIVE = 'active'
1065 BUILDING = 'building'
1066 DEPLOYWAIT = 'wait call-back'
1067 DEPLOYING = 'deploying'
1068 DEPLOYFAIL = 'deploy failed'
1069 DEPLOYDONE = 'deploy complete'
1070 DELETING = 'deleting'
1071 DELETED = 'deleted'
1072 ERROR = 'error'
1073
1074
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001075class BaremetalScenarioTest(ScenarioTest):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001076 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +01001077 def resource_setup(cls):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001078 if (not CONF.service_available.ironic or
1079 not CONF.baremetal.driver_enabled):
1080 msg = 'Ironic not available or Ironic compute driver not enabled'
1081 raise cls.skipException(msg)
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001082 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001083
1084 # use an admin client manager for baremetal client
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001085 manager = clients.Manager(
1086 credentials=cls.admin_credentials()
1087 )
Adam Gandelman4a48a602014-03-20 18:23:18 -07001088 cls.baremetal_client = manager.baremetal_client
1089
1090 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001091 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001092
1093 def _node_state_timeout(self, node_id, state_attr,
1094 target_states, timeout=10, interval=1):
1095 if not isinstance(target_states, list):
1096 target_states = [target_states]
1097
1098 def check_state():
1099 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001100 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001101 return True
1102 return False
1103
1104 if not tempest.test.call_until_true(
1105 check_state, timeout, interval):
1106 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1107 (node_id, state_attr, target_states))
1108 raise exceptions.TimeoutException(msg)
1109
1110 def wait_provisioning_state(self, node_id, state, timeout):
1111 self._node_state_timeout(
1112 node_id=node_id, state_attr='provision_state',
1113 target_states=state, timeout=timeout)
1114
1115 def wait_power_state(self, node_id, state):
1116 self._node_state_timeout(
1117 node_id=node_id, state_attr='power_state',
1118 target_states=state, timeout=CONF.baremetal.power_timeout)
1119
1120 def wait_node(self, instance_id):
1121 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001122
Adam Gandelman4a48a602014-03-20 18:23:18 -07001123 def _get_node():
1124 node = None
1125 try:
1126 node = self.get_node(instance_id=instance_id)
Andrea Frittoli2ddc2632014-09-25 11:03:00 +01001127 except exceptions.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001128 pass
1129 return node is not None
1130
1131 if not tempest.test.call_until_true(
1132 _get_node, CONF.baremetal.association_timeout, 1):
1133 msg = ('Timed out waiting to get Ironic node by instance id %s'
1134 % instance_id)
1135 raise exceptions.TimeoutException(msg)
1136
1137 def get_node(self, node_id=None, instance_id=None):
1138 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001139 _, body = self.baremetal_client.show_node(node_id)
1140 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001141 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001142 _, body = self.baremetal_client.show_node_by_instance_uuid(
1143 instance_id)
1144 if body['nodes']:
1145 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001146
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001147 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001148 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001149 _, body = self.baremetal_client.list_node_ports(node_uuid)
1150 for port in body['ports']:
1151 _, p = self.baremetal_client.show_port(port['uuid'])
1152 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001153 return ports
1154
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001155 def add_keypair(self):
1156 self.keypair = self.create_keypair()
1157
1158 def verify_connectivity(self, ip=None):
1159 if ip:
1160 dest = self.get_remote_client(ip)
1161 else:
1162 dest = self.get_remote_client(self.instance)
1163 dest.validate_authentication()
1164
1165 def boot_instance(self):
1166 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001167 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001168 }
1169 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001170 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001171
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001172 self.wait_node(self.instance['id'])
1173 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001174
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001175 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001176
1177 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001178 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001179 [BaremetalProvisionStates.DEPLOYWAIT,
1180 BaremetalProvisionStates.ACTIVE],
1181 timeout=15)
1182
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001183 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001184 BaremetalProvisionStates.ACTIVE,
1185 timeout=CONF.baremetal.active_timeout)
1186
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001187 self.servers_client.wait_for_server_status(self.instance['id'],
1188 'ACTIVE')
1189 self.node = self.get_node(instance_id=self.instance['id'])
1190 _, self.instance = self.servers_client.get_server(self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001191
1192 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001193 self.servers_client.delete_server(self.instance['id'])
1194 self.wait_power_state(self.node['uuid'],
1195 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001196 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001197 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001198 BaremetalProvisionStates.NOSTATE,
1199 timeout=CONF.baremetal.unprovision_timeout)
1200
Adam Gandelman4a48a602014-03-20 18:23:18 -07001201
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001202class EncryptionScenarioTest(ScenarioTest):
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001203 """
1204 Base class for encryption scenario tests
1205 """
1206
1207 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +01001208 def resource_setup(cls):
1209 super(EncryptionScenarioTest, cls).resource_setup()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001210 cls.admin_volume_types_client = cls.admin_manager.volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001211
1212 def _wait_for_volume_status(self, status):
1213 self.status_timeout(
1214 self.volume_client.volumes, self.volume.id, status)
1215
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001216 def nova_boot(self):
1217 self.keypair = self.create_keypair()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001218 create_kwargs = {'key_name': self.keypair['name']}
1219 self.server = self.create_server(image=self.image,
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001220 create_kwargs=create_kwargs)
1221
1222 def create_volume_type(self, client=None, name=None):
1223 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001224 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001225 if not name:
1226 name = 'generic'
1227 randomized_name = data_utils.rand_name('scenario-type-' + name + '-')
1228 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001229 body = client.create_volume_type(
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001230 randomized_name)
1231 self.assertIn('id', body)
1232 self.addCleanup(client.delete_volume_type, body['id'])
1233 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001234
1235 def create_encryption_type(self, client=None, type_id=None, provider=None,
1236 key_size=None, cipher=None,
1237 control_location=None):
1238 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001239 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001240 if not type_id:
1241 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001242 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001243 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001244 client.create_encryption_type(
1245 type_id, provider=provider, key_size=key_size, cipher=cipher,
1246 control_location=control_location)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001247
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001248
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +09001249class OrchestrationScenarioTest(ScenarioTest):
Steve Bakerdd7c6ce2013-06-24 14:46:47 +12001250 """
1251 Base class for orchestration scenario tests
1252 """
1253
1254 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +01001255 def resource_setup(cls):
Matthew Treinish6c072292014-01-29 19:15:52 +00001256 if not CONF.service_available.heat:
Matt Riedemann11c5b642013-08-24 08:45:38 -07001257 raise cls.skipException("Heat support is required")
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001258 super(OrchestrationScenarioTest, cls).resource_setup()
Matt Riedemann11c5b642013-08-24 08:45:38 -07001259
1260 @classmethod
Steve Bakerdd7c6ce2013-06-24 14:46:47 +12001261 def credentials(cls):
Andrea Frittoli422fbdf2014-03-20 10:05:18 +00001262 admin_creds = auth.get_default_credentials('identity_admin')
1263 creds = auth.get_default_credentials('user')
1264 admin_creds.tenant_name = creds.tenant_name
1265 return admin_creds
Steve Bakerdd7c6ce2013-06-24 14:46:47 +12001266
1267 def _load_template(self, base_file, file_name):
1268 filepath = os.path.join(os.path.dirname(os.path.realpath(base_file)),
1269 file_name)
1270 with open(filepath) as f:
1271 return f.read()
1272
1273 @classmethod
1274 def _stack_rand_name(cls):
Masayuki Igawa259c1132013-10-31 17:48:44 +09001275 return data_utils.rand_name(cls.__name__ + '-')
Steve Baker80252da2013-09-25 13:29:10 +12001276
1277 @classmethod
1278 def _get_default_network(cls):
David Kranz34e88122014-12-11 15:24:05 -05001279 networks = cls.networks_client.list_networks()
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +09001280 for net in networks:
1281 if net['label'] == CONF.compute.fixed_network_name:
Steve Baker80252da2013-09-25 13:29:10 +12001282 return net
Steve Baker22c16602014-05-05 13:34:19 +12001283
1284 @staticmethod
1285 def _stack_output(stack, output_key):
1286 """Return a stack output value for a given key."""
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +09001287 return next((o['output_value'] for o in stack['outputs']
Steve Baker22c16602014-05-05 13:34:19 +12001288 if o['output_key'] == output_key), None)
1289
Chris Dent0d494112014-08-26 13:48:30 +01001290
1291class SwiftScenarioTest(ScenarioTest):
1292 """
1293 Provide harness to do Swift scenario tests.
1294
1295 Subclasses implement the tests that use the methods provided by this
1296 class.
1297 """
1298
1299 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +01001300 def resource_setup(cls):
Chris Dent0d494112014-08-26 13:48:30 +01001301 if not CONF.service_available.swift:
1302 skip_msg = ("%s skipped as swift is not available" %
1303 cls.__name__)
1304 raise cls.skipException(skip_msg)
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001305 cls.set_network_resources()
1306 super(SwiftScenarioTest, cls).resource_setup()
Chris Dent0d494112014-08-26 13:48:30 +01001307 # Clients for Swift
1308 cls.account_client = cls.manager.account_client
1309 cls.container_client = cls.manager.container_client
1310 cls.object_client = cls.manager.object_client
1311
Chris Dentde456a12014-09-10 12:41:15 +01001312 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001313 """get swift status for our user account."""
1314 self.account_client.list_account_containers()
1315 LOG.debug('Swift status information obtained successfully')
1316
Chris Dentde456a12014-09-10 12:41:15 +01001317 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001318 name = container_name or data_utils.rand_name(
1319 'swift-scenario-container')
1320 self.container_client.create_container(name)
1321 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001322 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001323 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001324 self.addCleanup(self.delete_wrapper,
1325 self.container_client.delete_container,
1326 name)
Chris Dent0d494112014-08-26 13:48:30 +01001327 return name
1328
Chris Dentde456a12014-09-10 12:41:15 +01001329 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001330 self.container_client.delete_container(container_name)
1331 LOG.debug('Container %s deleted' % (container_name))
1332
Chris Dentde456a12014-09-10 12:41:15 +01001333 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001334 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1335 obj_data = data_utils.arbitrary_string()
1336 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001337 self.addCleanup(self.delete_wrapper,
1338 self.object_client.delete_object,
1339 container_name,
1340 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001341 return obj_name, obj_data
1342
Chris Dentde456a12014-09-10 12:41:15 +01001343 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001344 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001345 self.list_and_check_container_objects(container_name,
1346 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001347
Chris Dentde456a12014-09-10 12:41:15 +01001348 def list_and_check_container_objects(self, container_name,
1349 present_obj=None,
1350 not_present_obj=None):
Chris Dent0d494112014-08-26 13:48:30 +01001351 """
1352 List objects for a given container and assert which are present and
1353 which are not.
1354 """
Ghanshyam2a180b82014-06-16 13:54:22 +09001355 if present_obj is None:
1356 present_obj = []
1357 if not_present_obj is None:
1358 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001359 _, object_list = self.container_client.list_container_contents(
1360 container_name)
1361 if present_obj:
1362 for obj in present_obj:
1363 self.assertIn(obj, object_list)
1364 if not_present_obj:
1365 for obj in not_present_obj:
1366 self.assertNotIn(obj, object_list)
1367
Chris Dentde456a12014-09-10 12:41:15 +01001368 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001369 metadata_param = {'metadata_prefix': 'x-container-',
1370 'metadata': {'read': acl}}
1371 self.container_client.update_container_metadata(container_name,
1372 **metadata_param)
1373 resp, _ = self.container_client.list_container_metadata(container_name)
1374 self.assertEqual(resp['x-container-read'], acl)
1375
Chris Dentde456a12014-09-10 12:41:15 +01001376 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001377 _, obj = self.object_client.get_object(container_name, obj_name)
1378 self.assertEqual(obj, expected_data)