blob: 7e0c3b3b34773e9d9fa324e26243280783f602b2 [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
Matthew Treinish96e9e882014-06-09 18:37:19 -040021import six
Matthew Treinish01472ff2015-02-20 17:26:52 -050022from tempest_lib.common.utils import data_utils
Masayuki Igawad9388762015-01-20 14:56:42 +090023from tempest_lib import exceptions as lib_exc
Sean Dague6dbc6da2013-05-08 17:49:46 -040024
Andrea Frittolif9cde7e2014-02-18 09:57:04 +000025from tempest import clients
Rohan Kanade9ce97df2013-12-10 18:59:35 +053026from tempest.common import fixed_network
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
Yair Fried1fc32a12014-08-04 09:11:30 +030030from tempest.services.network import resources as net_resources
Sean Dague6dbc6da2013-05-08 17:49:46 -040031import tempest.test
Sean Dague6dbc6da2013-05-08 17:49:46 -040032
Matthew Treinish6c072292014-01-29 19:15:52 +000033CONF = config.CONF
Sean Dague6dbc6da2013-05-08 17:49:46 -040034
Attila Fazekasfb7552a2013-08-27 13:02:26 +020035LOG = log.getLogger(__name__)
36
Sean Dague6dbc6da2013-05-08 17:49:46 -040037
Andrea Frittoli2e733b52014-07-16 14:12:11 +010038class ScenarioTest(tempest.test.BaseTestCase):
Andrea Frittoli486ede72014-09-25 11:50:05 +010039 """Base class for scenario tests. Uses tempest own clients. """
Andrea Frittoli2e733b52014-07-16 14:12:11 +010040
Andrea Frittolib21de6c2015-02-06 20:12:38 +000041 credentials = ['primary']
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000042
43 @classmethod
44 def setup_clients(cls):
45 super(ScenarioTest, cls).setup_clients()
Andrea Frittoli247058f2014-07-16 16:09:22 +010046 # Clients (in alphabetical order)
Adam Gandelmanc78c7572014-08-28 18:38:55 -070047 cls.flavors_client = cls.manager.flavors_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010048 cls.floating_ips_client = cls.manager.floating_ips_client
49 # Glance image client v1
50 cls.image_client = cls.manager.image_client
nithya-ganesan882595e2014-07-29 18:51:07 +000051 # Compute image client
52 cls.images_client = cls.manager.images_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010053 cls.keypairs_client = cls.manager.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010054 # Nova security groups client
55 cls.security_groups_client = cls.manager.security_groups_client
56 cls.servers_client = cls.manager.servers_client
57 cls.volumes_client = cls.manager.volumes_client
Joseph Lanouxeef192f2014-08-01 14:32:53 +000058 cls.snapshots_client = cls.manager.snapshots_client
Yair Fried1fc32a12014-08-04 09:11:30 +030059 cls.interface_client = cls.manager.interfaces_client
60 # Neutron network client
61 cls.network_client = cls.manager.network_client
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090062 # Heat client
63 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010064
Andrea Frittoli247058f2014-07-16 16:09:22 +010065 # ## Methods to handle sync and async deletes
66
67 def setUp(self):
68 super(ScenarioTest, self).setUp()
69 self.cleanup_waits = []
70 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
71 # because scenario tests in the same test class should not share
72 # resources. If resources were shared between test cases then it
73 # should be a single scenario test instead of multiples.
74
75 # NOTE(yfried): this list is cleaned at the end of test_methods and
76 # not at the end of the class
77 self.addCleanup(self._wait_for_cleanups)
78
Yair Fried1fc32a12014-08-04 09:11:30 +030079 def delete_wrapper(self, delete_thing, *args, **kwargs):
Andrea Frittoli247058f2014-07-16 16:09:22 +010080 """Ignores NotFound exceptions for delete operations.
81
Yair Fried1fc32a12014-08-04 09:11:30 +030082 @param delete_thing: delete method of a resource. method will be
83 executed as delete_thing(*args, **kwargs)
84
Andrea Frittoli247058f2014-07-16 16:09:22 +010085 """
86 try:
87 # Tempest clients return dicts, so there is no common delete
88 # method available. Using a callable instead
Yair Fried1fc32a12014-08-04 09:11:30 +030089 delete_thing(*args, **kwargs)
Masayuki Igawabfa07602015-01-20 18:47:17 +090090 except lib_exc.NotFound:
Andrea Frittoli247058f2014-07-16 16:09:22 +010091 # If the resource is already missing, mission accomplished.
92 pass
93
94 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +090095 cleanup_callable, cleanup_args=None,
96 cleanup_kwargs=None, ignore_error=True):
Adam Gandelmanc78c7572014-08-28 18:38:55 -070097 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +010098
99 @param waiter_callable: callable to wait for the resource to delete
100 @param thing_id: the id of the resource to be cleaned-up
101 @param thing_id_param: the name of the id param in the waiter
102 @param cleanup_callable: method to load pass to self.addCleanup with
103 the following *cleanup_args, **cleanup_kwargs.
104 usually a delete method.
105 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900106 if cleanup_args is None:
107 cleanup_args = []
108 if cleanup_kwargs is None:
109 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100110 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
111 wait_dict = {
112 'waiter_callable': waiter_callable,
113 thing_id_param: thing_id
114 }
115 self.cleanup_waits.append(wait_dict)
116
117 def _wait_for_cleanups(self):
118 """To handle async delete actions, a list of waits is added
119 which will be iterated over as the last step of clearing the
120 cleanup queue. That way all the delete calls are made up front
121 and the tests won't succeed unless the deletes are eventually
122 successful. This is the same basic approach used in the api tests to
123 limit cleanup execution time except here it is multi-resource,
124 because of the nature of the scenario tests.
125 """
126 for wait in self.cleanup_waits:
127 waiter_callable = wait.pop('waiter_callable')
128 waiter_callable(**wait)
129
130 # ## Test functions library
131 #
132 # The create_[resource] functions only return body and discard the
133 # resp part which is not used in scenario tests
134
Yair Frieddb6c9e92014-08-06 08:53:13 +0300135 def create_keypair(self, client=None):
136 if not client:
137 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100138 name = data_utils.rand_name(self.__class__.__name__)
139 # We don't need to create a keypair by pubkey in scenario
David Kranz173f0e02015-02-06 13:47:57 -0500140 body = client.create_keypair(name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300141 self.addCleanup(client.delete_keypair, name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100142 return body
143
144 def create_server(self, name=None, image=None, flavor=None,
145 wait_on_boot=True, wait_on_delete=True,
Ghanshyam2a180b82014-06-16 13:54:22 +0900146 create_kwargs=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100147 """Creates VM instance.
148
149 @param image: image from which to create the instance
150 @param wait_on_boot: wait for status ACTIVE before continue
151 @param wait_on_delete: force synchronous delete on cleanup
152 @param create_kwargs: additional details for instance creation
153 @return: server dict
154 """
155 if name is None:
156 name = data_utils.rand_name(self.__class__.__name__)
157 if image is None:
158 image = CONF.compute.image_ref
159 if flavor is None:
160 flavor = CONF.compute.flavor_ref
Ghanshyam2a180b82014-06-16 13:54:22 +0900161 if create_kwargs is None:
162 create_kwargs = {}
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530163 network = self.get_tenant_network()
Matthew Treinish4bbc1992015-04-07 11:13:40 -0400164 create_kwargs = fixed_network.set_networks_kwarg(network,
165 create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100166
Andrea Frittoli247058f2014-07-16 16:09:22 +0100167 LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
168 name, image, flavor)
David Kranz0fb14292015-02-11 15:55:20 -0500169 server = self.servers_client.create_server(name, image, flavor,
170 **create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100171 if wait_on_delete:
172 self.addCleanup(self.servers_client.wait_for_server_termination,
173 server['id'])
174 self.addCleanup_with_wait(
175 waiter_callable=self.servers_client.wait_for_server_termination,
176 thing_id=server['id'], thing_id_param='server_id',
177 cleanup_callable=self.delete_wrapper,
178 cleanup_args=[self.servers_client.delete_server, server['id']])
179 if wait_on_boot:
180 self.servers_client.wait_for_server_status(server_id=server['id'],
181 status='ACTIVE')
182 # The instance retrieved on creation is missing network
183 # details, necessitating retrieval after it becomes active to
184 # ensure correct details.
David Kranz0fb14292015-02-11 15:55:20 -0500185 server = self.servers_client.get_server(server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100186 self.assertEqual(server['name'], name)
187 return server
188
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100189 def create_volume(self, size=None, name=None, snapshot_id=None,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100190 imageRef=None, volume_type=None, wait_on_delete=True):
191 if name is None:
192 name = data_utils.rand_name(self.__class__.__name__)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000193 volume = self.volumes_client.create_volume(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100194 size=size, display_name=name, snapshot_id=snapshot_id,
195 imageRef=imageRef, volume_type=volume_type)
Matt Riedemanne85c2702014-09-10 11:50:13 -0700196
Andrea Frittoli247058f2014-07-16 16:09:22 +0100197 if wait_on_delete:
198 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
199 volume['id'])
Matt Riedemanne85c2702014-09-10 11:50:13 -0700200 self.addCleanup(self.delete_wrapper,
201 self.volumes_client.delete_volume, volume['id'])
202 else:
203 self.addCleanup_with_wait(
204 waiter_callable=self.volumes_client.wait_for_resource_deletion,
205 thing_id=volume['id'], thing_id_param='id',
206 cleanup_callable=self.delete_wrapper,
207 cleanup_args=[self.volumes_client.delete_volume, volume['id']])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100208
209 self.assertEqual(name, volume['display_name'])
210 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
211 # The volume retrieved on creation has a non-up-to-date status.
212 # Retrieval after it becomes active ensures correct details.
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000213 volume = self.volumes_client.show_volume(volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100214 return volume
215
Yair Fried1fc32a12014-08-04 09:11:30 +0300216 def _create_loginable_secgroup_rule(self, secgroup_id=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100217 _client = self.security_groups_client
218 if secgroup_id is None:
David Kranz9964b4e2015-02-06 15:45:29 -0500219 sgs = _client.list_security_groups()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100220 for sg in sgs:
221 if sg['name'] == 'default':
222 secgroup_id = sg['id']
223
224 # These rules are intended to permit inbound ssh and icmp
225 # traffic from all sources, so no group_id is provided.
226 # Setting a group_id would only permit traffic from ports
227 # belonging to the same security group.
228 rulesets = [
229 {
230 # ssh
231 'ip_proto': 'tcp',
232 'from_port': 22,
233 'to_port': 22,
234 'cidr': '0.0.0.0/0',
235 },
236 {
237 # ping
238 'ip_proto': 'icmp',
239 'from_port': -1,
240 'to_port': -1,
241 'cidr': '0.0.0.0/0',
242 }
243 ]
244 rules = list()
245 for ruleset in rulesets:
David Kranz9964b4e2015-02-06 15:45:29 -0500246 sg_rule = _client.create_security_group_rule(secgroup_id,
247 **ruleset)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100248 self.addCleanup(self.delete_wrapper,
249 _client.delete_security_group_rule,
250 sg_rule['id'])
251 rules.append(sg_rule)
252 return rules
253
Yair Fried1fc32a12014-08-04 09:11:30 +0300254 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100255 # Create security group
256 sg_name = data_utils.rand_name(self.__class__.__name__)
257 sg_desc = sg_name + " description"
David Kranz9964b4e2015-02-06 15:45:29 -0500258 secgroup = self.security_groups_client.create_security_group(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100259 sg_name, sg_desc)
260 self.assertEqual(secgroup['name'], sg_name)
261 self.assertEqual(secgroup['description'], sg_desc)
262 self.addCleanup(self.delete_wrapper,
263 self.security_groups_client.delete_security_group,
264 secgroup['id'])
265
266 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300267 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100268
269 return secgroup
270
JordanP3fe2dc32014-11-17 13:06:01 +0100271 def get_remote_client(self, server_or_ip, username=None, private_key=None,
272 log_console_of_servers=None):
273 """Get a SSH client to a remote server
274
275 @param server_or_ip a server object as returned by Tempest compute
276 client or an IP address to connect to
277 @param username name of the Linux account on the remote server
278 @param private_key the SSH private key to use
279 @param log_console_of_servers a list of server objects. Each server
280 in the list will have its console printed in the logs in case the
281 SSH connection failed to be established
282 @return a RemoteClient object
283 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100284 if isinstance(server_or_ip, six.string_types):
285 ip = server_or_ip
286 else:
Andrew Boik4a3daf12015-03-27 01:59:31 -0400287 addrs = server_or_ip['addresses'][CONF.compute.network_for_ssh]
288 try:
289 ip = (addr['addr'] for addr in addrs if
290 netaddr.valid_ipv4(addr['addr'])).next()
291 except StopIteration:
292 raise lib_exc.NotFound("No IPv4 addresses to use for SSH to "
293 "remote server.")
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700294
Andrea Frittoli247058f2014-07-16 16:09:22 +0100295 if username is None:
296 username = CONF.scenario.ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800297 # Set this with 'keypair' or others to log in with keypair or
298 # username/password.
299 if CONF.compute.ssh_auth_method == 'keypair':
300 password = None
301 if private_key is None:
302 private_key = self.keypair['private_key']
303 else:
304 password = CONF.compute.image_ssh_password
305 private_key = None
Andrea Frittoli247058f2014-07-16 16:09:22 +0100306 linux_client = remote_client.RemoteClient(ip, username,
wantwatering896300c2015-03-27 15:17:42 +0800307 pkey=private_key,
308 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100309 try:
310 linux_client.validate_authentication()
JordanP3fe2dc32014-11-17 13:06:01 +0100311 except Exception:
312 LOG.exception('Initializing SSH connection to %s failed' % ip)
Marc Kodererb06db502015-04-30 09:31:27 +0200313 # If we don't explicitly set for which servers we want to
JordanP3fe2dc32014-11-17 13:06:01 +0100314 # log the console output then all the servers will be logged.
315 # See the definition of _log_console_output()
316 self._log_console_output(log_console_of_servers)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100317 raise
318
319 return linux_client
320
Ghanshyam2a180b82014-06-16 13:54:22 +0900321 def _image_create(self, name, fmt, path, properties=None):
322 if properties is None:
323 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100324 name = data_utils.rand_name('%s-' % name)
325 image_file = open(path, 'rb')
326 self.addCleanup(image_file.close)
327 params = {
328 'name': name,
329 'container_format': fmt,
330 'disk_format': fmt,
331 'is_public': 'False',
332 }
333 params.update(properties)
David Kranz34f18782015-01-06 13:43:55 -0500334 image = self.image_client.create_image(**params)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100335 self.addCleanup(self.image_client.delete_image, image['id'])
336 self.assertEqual("queued", image['status'])
337 self.image_client.update_image(image['id'], data=image_file)
338 return image['id']
339
340 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300341 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100342 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
343 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
344 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300345 img_container_format = CONF.scenario.img_container_format
346 img_disk_format = CONF.scenario.img_disk_format
347 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
348 "ami: %s, ari: %s, aki: %s" %
349 (img_path, img_container_format, img_disk_format,
350 ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100351 try:
352 self.image = self._image_create('scenario-img',
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300353 img_container_format,
354 img_path,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100355 properties={'disk_format':
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300356 img_disk_format})
Andrea Frittoli247058f2014-07-16 16:09:22 +0100357 except IOError:
358 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
359 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
360 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
361 properties = {
362 'properties': {'kernel_id': kernel, 'ramdisk_id': ramdisk}
363 }
364 self.image = self._image_create('scenario-ami', 'ami',
365 path=ami_img_path,
366 properties=properties)
367 LOG.debug("image:%s" % self.image)
368
369 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400370 if not CONF.compute_feature_enabled.console_output:
371 LOG.debug('Console output not supported, cannot log')
372 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100373 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500374 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100375 servers = servers['servers']
376 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500377 console_output = self.servers_client.get_console_output(
David Kranzae99b9a2015-02-16 13:37:01 -0500378 server['id'], length=None).data
379 LOG.debug('Console output for %s\nbody=\n%s',
380 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100381
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000382 def _log_net_info(self, exc):
383 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300384 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000385 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000386
nithya-ganesan882595e2014-07-29 18:51:07 +0000387 def create_server_snapshot(self, server, name=None):
388 # Glance client
389 _image_client = self.image_client
390 # Compute client
391 _images_client = self.images_client
392 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000393 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000394 LOG.debug("Creating a snapshot image for server: %s", server['name'])
David Kranza5299eb2015-01-15 17:24:05 -0500395 image = _images_client.create_image(server['id'], name)
396 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000397 _image_client.wait_for_image_status(image_id, 'active')
398 self.addCleanup_with_wait(
399 waiter_callable=_image_client.wait_for_resource_deletion,
400 thing_id=image_id, thing_id_param='id',
401 cleanup_callable=self.delete_wrapper,
402 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500403 snapshot_image = _image_client.get_image_meta(image_id)
nithya-ganesan882595e2014-07-29 18:51:07 +0000404 image_name = snapshot_image['name']
405 self.assertEqual(name, image_name)
406 LOG.debug("Created snapshot image %s for server %s",
407 image_name, server['name'])
408 return snapshot_image
409
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900410 def nova_volume_attach(self):
411 # TODO(andreaf) Device should be here CONF.compute.volume_device_name
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000412 volume = self.servers_client.attach_volume(
David Kranz3ebc7212015-02-10 12:19:19 -0500413 self.server['id'], self.volume['id'], '/dev/vdb')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900414 self.assertEqual(self.volume['id'], volume['id'])
415 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
416 # Refresh the volume after the attachment
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000417 self.volume = self.volumes_client.show_volume(volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900418
419 def nova_volume_detach(self):
420 self.servers_client.detach_volume(self.server['id'], self.volume['id'])
421 self.volumes_client.wait_for_volume_status(self.volume['id'],
422 'available')
423
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000424 volume = self.volumes_client.show_volume(self.volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900425 self.assertEqual('available', volume['status'])
426
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700427 def rebuild_server(self, server_id, image=None,
428 preserve_ephemeral=False, wait=True,
429 rebuild_kwargs=None):
430 if image is None:
431 image = CONF.compute.image_ref
432
433 rebuild_kwargs = rebuild_kwargs or {}
434
435 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
436 server_id, image, preserve_ephemeral)
437 self.servers_client.rebuild(server_id=server_id, image_ref=image,
438 preserve_ephemeral=preserve_ephemeral,
439 **rebuild_kwargs)
440 if wait:
441 self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
442
Steven Hardyda2a8352014-10-02 12:52:20 +0100443 def ping_ip_address(self, ip_address, should_succeed=True,
444 ping_timeout=None):
445 timeout = ping_timeout or CONF.compute.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700446 cmd = ['ping', '-c1', '-w1', ip_address]
447
448 def ping():
449 proc = subprocess.Popen(cmd,
450 stdout=subprocess.PIPE,
451 stderr=subprocess.PIPE)
452 proc.communicate()
453 return (proc.returncode == 0) == should_succeed
454
Steven Hardyda2a8352014-10-02 12:52:20 +0100455 return tempest.test.call_until_true(ping, timeout, 1)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700456
Yair Friedae0e73d2014-11-24 11:56:26 +0200457 def check_vm_connectivity(self, ip_address,
458 username=None,
459 private_key=None,
460 should_connect=True):
461 """
462 :param ip_address: server to test against
463 :param username: server's ssh username
464 :param private_key: server's ssh private key to be used
465 :param should_connect: True/False indicates positive/negative test
466 positive - attempt ping and ssh
467 negative - attempt ping and fail if succeed
468
469 :raises: AssertError if the result of the connectivity check does
470 not match the value of the should_connect param
471 """
472 if should_connect:
473 msg = "Timed out waiting for %s to become reachable" % ip_address
474 else:
475 msg = "ip address %s is reachable" % ip_address
476 self.assertTrue(self.ping_ip_address(ip_address,
477 should_succeed=should_connect),
478 msg=msg)
479 if should_connect:
480 # no need to check ssh for negative connectivity
481 self.get_remote_client(ip_address, username, private_key)
482
483 def check_public_network_connectivity(self, ip_address, username,
484 private_key, should_connect=True,
485 msg=None, servers=None):
486 # The target login is assumed to have been configured for
487 # key-based authentication by cloud-init.
488 LOG.debug('checking network connections to IP %s with user: %s' %
489 (ip_address, username))
490 try:
491 self.check_vm_connectivity(ip_address,
492 username,
493 private_key,
494 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500495 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200496 ex_msg = 'Public network connectivity check failed'
497 if msg:
498 ex_msg += ": " + msg
499 LOG.exception(ex_msg)
500 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200501 raise
502
503 def create_floating_ip(self, thing, pool_name=None):
504 """Creates a floating IP and associates to a server using
505 Nova clients
506 """
507
David Kranze4e3b412015-02-10 10:50:42 -0500508 floating_ip = self.floating_ips_client.create_floating_ip(pool_name)
Yair Friedae0e73d2014-11-24 11:56:26 +0200509 self.addCleanup(self.delete_wrapper,
510 self.floating_ips_client.delete_floating_ip,
511 floating_ip['id'])
512 self.floating_ips_client.associate_floating_ip_to_server(
513 floating_ip['ip'], thing['id'])
514 return floating_ip
515
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100516
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100517class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300518 """Base class for network scenario tests.
519 This class provide helpers for network scenario tests, using the neutron
520 API. Helpers from ancestor which use the nova network API are overridden
521 with the neutron API.
522
523 This Class also enforces using Neutron instead of novanetwork.
524 Subclassed tests will be skipped if Neutron is not enabled
525
526 """
527
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000528 credentials = ['primary', 'admin']
529
Yair Fried1fc32a12014-08-04 09:11:30 +0300530 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000531 def skip_checks(cls):
532 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100533 if not CONF.service_available.neutron:
534 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300535
536 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100537 def resource_setup(cls):
538 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300539 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300540
Yair Frieddb6c9e92014-08-06 08:53:13 +0300541 def _create_network(self, client=None, tenant_id=None,
542 namestart='network-smoke-'):
543 if not client:
544 client = self.network_client
545 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000546 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300547 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500548 result = client.create_network(name=name, tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300549 network = net_resources.DeletableNetwork(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300550 **result['network'])
551 self.assertEqual(network.name, name)
552 self.addCleanup(self.delete_wrapper, network.delete)
553 return network
554
555 def _list_networks(self, *args, **kwargs):
556 """List networks using admin creds """
557 return self._admin_lister('networks')(*args, **kwargs)
558
559 def _list_subnets(self, *args, **kwargs):
560 """List subnets using admin creds """
561 return self._admin_lister('subnets')(*args, **kwargs)
562
563 def _list_routers(self, *args, **kwargs):
564 """List routers using admin creds """
565 return self._admin_lister('routers')(*args, **kwargs)
566
567 def _list_ports(self, *args, **kwargs):
568 """List ports using admin creds """
569 return self._admin_lister('ports')(*args, **kwargs)
570
571 def _admin_lister(self, resource_type):
572 def temp(*args, **kwargs):
573 temp_method = self.admin_manager.network_client.__getattr__(
574 'list_%s' % resource_type)
David Kranz34e88122014-12-11 15:24:05 -0500575 resource_list = temp_method(*args, **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300576 return resource_list[resource_type]
577 return temp
578
Yair Frieddb6c9e92014-08-06 08:53:13 +0300579 def _create_subnet(self, network, client=None, namestart='subnet-smoke',
580 **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300581 """
582 Create a subnet for the given network within the cidr block
583 configured for tenant networks.
584 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300585 if not client:
586 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300587
588 def cidr_in_use(cidr, tenant_id):
589 """
590 :return True if subnet with cidr already exist in tenant
591 False else
592 """
593 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
594 return len(cidr_in_use) != 0
595
Kirill Shileev14113572014-11-21 16:58:02 +0300596 ip_version = kwargs.pop('ip_version', 4)
597
598 if ip_version == 6:
599 tenant_cidr = netaddr.IPNetwork(
600 CONF.network.tenant_network_v6_cidr)
601 num_bits = CONF.network.tenant_network_v6_mask_bits
602 else:
603 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
604 num_bits = CONF.network.tenant_network_mask_bits
605
Yair Fried1fc32a12014-08-04 09:11:30 +0300606 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300607 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300608 # Repeatedly attempt subnet creation with sequential cidr
609 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300610 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300611 str_cidr = str(subnet_cidr)
612 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
613 continue
614
615 subnet = dict(
616 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300617 network_id=network.id,
618 tenant_id=network.tenant_id,
619 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300620 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300621 **kwargs
622 )
623 try:
David Kranz34e88122014-12-11 15:24:05 -0500624 result = client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300625 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900626 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300627 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
628 if not is_overlapping_cidr:
629 raise
630 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300631 subnet = net_resources.DeletableSubnet(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300632 **result['subnet'])
633 self.assertEqual(subnet.cidr, str_cidr)
634 self.addCleanup(self.delete_wrapper, subnet.delete)
635 return subnet
636
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200637 def _create_port(self, network_id, client=None, namestart='port-quotatest',
638 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300639 if not client:
640 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300641 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500642 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300643 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200644 network_id=network_id,
645 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300646 self.assertIsNotNone(result, 'Unable to allocate port')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300647 port = net_resources.DeletablePort(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300648 **result['port'])
649 self.addCleanup(self.delete_wrapper, port.delete)
650 return port
651
Kirill Shileev14113572014-11-21 16:58:02 +0300652 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300653 ports = self._list_ports(device_id=server['id'],
654 fixed_ip=ip_addr)
655 self.assertEqual(len(ports), 1,
656 "Unable to determine which port to target.")
Kirill Shileev14113572014-11-21 16:58:02 +0300657 # it might happen here that this port has more then one ip address
658 # as in case of dual stack- when this port is created on 2 subnets
659 for ip46 in ports[0]['fixed_ips']:
660 ip = ip46['ip_address']
661 if netaddr.valid_ipv4(ip):
662 return ports[0]['id'], ip
Yair Fried1fc32a12014-08-04 09:11:30 +0300663
David Shrewsbury9bac3662014-08-07 15:07:01 -0400664 def _get_network_by_name(self, network_name):
665 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700666 self.assertNotEqual(len(net), 0,
667 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300668 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400669
Yair Friedae0e73d2014-11-24 11:56:26 +0200670 def create_floating_ip(self, thing, external_network_id=None,
671 port_id=None, client=None):
672 """Creates a floating IP and associates to a resource/port using
673 Neutron client
674 """
675 if not external_network_id:
676 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300677 if not client:
678 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300679 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300680 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
681 else:
682 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500683 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300684 floating_network_id=external_network_id,
685 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300686 tenant_id=thing['tenant_id'],
687 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300688 )
689 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300690 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300691 **result['floatingip'])
692 self.addCleanup(self.delete_wrapper, floating_ip.delete)
693 return floating_ip
694
695 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300696 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300697 floating_ip.update(port_id=port_id)
698 self.assertEqual(port_id, floating_ip.port_id)
699 return floating_ip
700
701 def _disassociate_floating_ip(self, floating_ip):
702 """
703 :param floating_ip: type DeletableFloatingIp
704 """
705 floating_ip.update(port_id=None)
706 self.assertIsNone(floating_ip.port_id)
707 return floating_ip
708
Yair Fried45f92952014-06-26 05:19:19 +0300709 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000710 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300711
712 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
713 to check status
714 :param status: target status
715 :raises: AssertionError if status doesn't match
716 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000717 def refresh():
718 floating_ip.refresh()
719 return status == floating_ip.status
720
721 tempest.test.call_until_true(refresh,
722 CONF.network.build_timeout,
723 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300724 self.assertEqual(status, floating_ip.status,
725 message="FloatingIP: {fp} is at status: {cst}. "
726 "failed to reach status: {st}"
727 .format(fp=floating_ip, cst=floating_ip.status,
728 st=status))
729 LOG.info("FloatingIP: {fp} is at status: {st}"
730 .format(fp=floating_ip, st=status))
731
Yair Fried1fc32a12014-08-04 09:11:30 +0300732 def _check_tenant_network_connectivity(self, server,
733 username,
734 private_key,
735 should_connect=True,
736 servers_for_debug=None):
737 if not CONF.network.tenant_networks_reachable:
738 msg = 'Tenant networks not configured to be reachable.'
739 LOG.info(msg)
740 return
741 # The target login is assumed to have been configured for
742 # key-based authentication by cloud-init.
743 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400744 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300745 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900746 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200747 username,
748 private_key,
749 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300750 except Exception as e:
751 LOG.exception('Tenant network connectivity check failed')
752 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000753 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300754 raise
755
756 def _check_remote_connectivity(self, source, dest, should_succeed=True):
757 """
758 check ping server via source ssh connection
759
760 :param source: RemoteClient: an ssh connection from which to ping
761 :param dest: and IP to ping against
762 :param should_succeed: boolean should ping succeed or not
763 :returns: boolean -- should_succeed == ping
764 :returns: ping is false if ping failed
765 """
766 def ping_remote():
767 try:
768 source.ping_host(dest)
Andrey Pavlov64723762015-04-29 06:24:58 +0300769 except lib_exc.SSHExecCommandFailed:
Yair Fried1fc32a12014-08-04 09:11:30 +0300770 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
771 % (dest, source.ssh_client.host))
772 return not should_succeed
773 return should_succeed
774
775 return tempest.test.call_until_true(ping_remote,
776 CONF.compute.ping_timeout,
777 1)
778
Yair Frieddb6c9e92014-08-06 08:53:13 +0300779 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300780 namestart='secgroup-smoke'):
781 if client is None:
782 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300783 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000784 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300785 secgroup = self._create_empty_security_group(namestart=namestart,
786 client=client,
787 tenant_id=tenant_id)
788
789 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900790 rules = self._create_loginable_secgroup_rule(client=client,
791 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300792 for rule in rules:
793 self.assertEqual(tenant_id, rule.tenant_id)
794 self.assertEqual(secgroup.id, rule.security_group_id)
795 return secgroup
796
Yair Frieddb6c9e92014-08-06 08:53:13 +0300797 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300798 namestart='secgroup-smoke'):
799 """Create a security group without rules.
800
801 Default rules will be created:
802 - IPv4 egress to any
803 - IPv6 egress to any
804
805 :param tenant_id: secgroup will be created in this tenant
806 :returns: DeletableSecurityGroup -- containing the secgroup created
807 """
808 if client is None:
809 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300810 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000811 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300812 sg_name = data_utils.rand_name(namestart)
813 sg_desc = sg_name + " description"
814 sg_dict = dict(name=sg_name,
815 description=sg_desc)
816 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500817 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300818 secgroup = net_resources.DeletableSecurityGroup(
819 client=client,
820 **result['security_group']
821 )
822 self.assertEqual(secgroup.name, sg_name)
823 self.assertEqual(tenant_id, secgroup.tenant_id)
824 self.assertEqual(secgroup.description, sg_desc)
825 self.addCleanup(self.delete_wrapper, secgroup.delete)
826 return secgroup
827
Yair Frieddb6c9e92014-08-06 08:53:13 +0300828 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300829 """Get default secgroup for given tenant_id.
830
831 :returns: DeletableSecurityGroup -- default secgroup for given tenant
832 """
833 if client is None:
834 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300835 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000836 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300837 sgs = [
838 sg for sg in client.list_security_groups().values()[0]
839 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
840 ]
841 msg = "No default security group for tenant %s." % (tenant_id)
842 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300843 return net_resources.DeletableSecurityGroup(client=client,
844 **sgs[0])
845
Yair Frieddb6c9e92014-08-06 08:53:13 +0300846 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300847 tenant_id=None, **kwargs):
848 """Create a rule from a dictionary of rule parameters.
849
850 Create a rule in a secgroup. if secgroup not defined will search for
851 default secgroup in tenant_id.
852
853 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300854 :param tenant_id: if secgroup not passed -- the tenant in which to
855 search for default secgroup
856 :param kwargs: a dictionary containing rule parameters:
857 for example, to allow incoming ssh:
858 rule = {
859 direction: 'ingress'
860 protocol:'tcp',
861 port_range_min: 22,
862 port_range_max: 22
863 }
864 """
865 if client is None:
866 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300867 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000868 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300869 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300870 secgroup = self._default_security_group(client=client,
871 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300872
873 ruleset = dict(security_group_id=secgroup.id,
874 tenant_id=secgroup.tenant_id)
875 ruleset.update(kwargs)
876
David Kranz34e88122014-12-11 15:24:05 -0500877 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300878 sg_rule = net_resources.DeletableSecurityGroupRule(
879 client=client,
880 **sg_rule['security_group_rule']
881 )
882 self.addCleanup(self.delete_wrapper, sg_rule.delete)
883 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
884 self.assertEqual(secgroup.id, sg_rule.security_group_id)
885
886 return sg_rule
887
888 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
889 """These rules are intended to permit inbound ssh and icmp
890 traffic from all sources, so no group_id is provided.
891 Setting a group_id would only permit traffic from ports
892 belonging to the same security group.
893 """
894
895 if client is None:
896 client = self.network_client
897 rules = []
898 rulesets = [
899 dict(
900 # ssh
901 protocol='tcp',
902 port_range_min=22,
903 port_range_max=22,
904 ),
905 dict(
906 # ping
907 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +0100908 ),
909 dict(
910 # ipv6-icmp for ping6
911 protocol='icmp',
912 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +0300913 )
914 ]
915 for ruleset in rulesets:
916 for r_direction in ['ingress', 'egress']:
917 ruleset['direction'] = r_direction
918 try:
919 sg_rule = self._create_security_group_rule(
920 client=client, secgroup=secgroup, **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +0900921 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +0300922 # if rule already exist - skip rule and continue
923 msg = 'Security group rule already exists'
924 if msg not in ex._error_string:
925 raise ex
926 else:
927 self.assertEqual(r_direction, sg_rule.direction)
928 rules.append(sg_rule)
929
930 return rules
931
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500932 def _create_pool(self, lb_method, protocol, subnet_id):
933 """Wrapper utility that returns a test pool."""
934 client = self.network_client
935 name = data_utils.rand_name('pool')
David Kranz34e88122014-12-11 15:24:05 -0500936 resp_pool = client.create_pool(protocol=protocol, name=name,
937 subnet_id=subnet_id,
938 lb_method=lb_method)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500939 pool = net_resources.DeletablePool(client=client, **resp_pool['pool'])
940 self.assertEqual(pool['name'], name)
941 self.addCleanup(self.delete_wrapper, pool.delete)
942 return pool
943
944 def _create_member(self, address, protocol_port, pool_id):
945 """Wrapper utility that returns a test member."""
946 client = self.network_client
David Kranz34e88122014-12-11 15:24:05 -0500947 resp_member = client.create_member(protocol_port=protocol_port,
948 pool_id=pool_id,
949 address=address)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500950 member = net_resources.DeletableMember(client=client,
951 **resp_member['member'])
952 self.addCleanup(self.delete_wrapper, member.delete)
953 return member
954
955 def _create_vip(self, protocol, protocol_port, subnet_id, pool_id):
956 """Wrapper utility that returns a test vip."""
957 client = self.network_client
958 name = data_utils.rand_name('vip')
David Kranz34e88122014-12-11 15:24:05 -0500959 resp_vip = client.create_vip(protocol=protocol, name=name,
960 subnet_id=subnet_id, pool_id=pool_id,
961 protocol_port=protocol_port)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500962 vip = net_resources.DeletableVip(client=client, **resp_vip['vip'])
963 self.assertEqual(vip['name'], name)
964 self.addCleanup(self.delete_wrapper, vip.delete)
965 return vip
966
Yair Fried1fc32a12014-08-04 09:11:30 +0300967 def _ssh_to_server(self, server, private_key):
968 ssh_login = CONF.compute.image_ssh_user
969 return self.get_remote_client(server,
970 username=ssh_login,
971 private_key=private_key)
972
Yair Frieddb6c9e92014-08-06 08:53:13 +0300973 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300974 """Retrieve a router for the given tenant id.
975
976 If a public router has been configured, it will be returned.
977
978 If a public router has not been configured, but a public
979 network has, a tenant router will be created and returned that
980 routes traffic to the public network.
981 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300982 if not client:
983 client = self.network_client
984 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000985 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300986 router_id = CONF.network.public_router_id
987 network_id = CONF.network.public_network_id
988 if router_id:
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +0400989 resp, body = client.show_router(router_id)
990 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300991 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300992 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300993 router.set_gateway(network_id)
994 return router
995 else:
996 raise Exception("Neither of 'public_router_id' or "
997 "'public_network_id' has been defined.")
998
Yair Frieddb6c9e92014-08-06 08:53:13 +0300999 def _create_router(self, client=None, tenant_id=None,
1000 namestart='router-smoke'):
1001 if not client:
1002 client = self.network_client
1003 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001004 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001005 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001006 result = client.create_router(name=name,
1007 admin_state_up=True,
1008 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001009 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001010 **result['router'])
1011 self.assertEqual(router.name, name)
1012 self.addCleanup(self.delete_wrapper, router.delete)
1013 return router
1014
Alok Maurya6384bbb2014-07-13 06:44:29 -07001015 def _update_router_admin_state(self, router, admin_state_up):
1016 router.update(admin_state_up=admin_state_up)
1017 self.assertEqual(admin_state_up, router.admin_state_up)
1018
Yair Fried413bf2d2014-11-19 17:07:11 +02001019 def create_networks(self, client=None, tenant_id=None,
1020 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001021 """Create a network with a subnet connected to a router.
1022
David Shrewsbury9bac3662014-08-07 15:07:01 -04001023 The baremetal driver is a special case since all nodes are
1024 on the same shared network.
1025
Yair Fried413bf2d2014-11-19 17:07:11 +02001026 :param client: network client to create resources with.
1027 :param tenant_id: id of tenant to create resources in.
1028 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001029 :returns: network, subnet, router
1030 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001031 if CONF.baremetal.driver_enabled:
1032 # NOTE(Shrews): This exception is for environments where tenant
1033 # credential isolation is available, but network separation is
1034 # not (the current baremetal case). Likely can be removed when
1035 # test account mgmt is reworked:
1036 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001037 if not CONF.compute.fixed_network_name:
1038 m = 'fixed_network_name must be specified in config'
1039 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001040 network = self._get_network_by_name(
1041 CONF.compute.fixed_network_name)
1042 router = None
1043 subnet = None
1044 else:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001045 network = self._create_network(client=client, tenant_id=tenant_id)
1046 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001047
1048 subnet_kwargs = dict(network=network, client=client)
1049 # use explicit check because empty list is a valid option
1050 if dns_nameservers is not None:
1051 subnet_kwargs['dns_nameservers'] = dns_nameservers
1052 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001053 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001054 return network, subnet, router
1055
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001056 def create_server(self, name=None, image=None, flavor=None,
1057 wait_on_boot=True, wait_on_delete=True,
1058 create_kwargs=None):
1059 vnic_type = CONF.network.port_vnic_type
1060
1061 # If vnic_type is configured create port for
1062 # every network
1063 if vnic_type:
1064 ports = []
1065 networks = []
1066 create_port_body = {'binding:vnic_type': vnic_type,
1067 'namestart': 'port-smoke'}
1068 if create_kwargs:
1069 net_client = create_kwargs.get("network_client",
1070 self.network_client)
1071
1072 # Convert security group names to security group ids
1073 # to pass to create_port
1074 if create_kwargs.get('security_groups'):
1075 security_groups = net_client.list_security_groups().get(
1076 'security_groups')
1077 sec_dict = dict([(s['name'], s['id'])
1078 for s in security_groups])
1079
1080 sec_groups_names = [s['name'] for s in create_kwargs[
1081 'security_groups']]
1082 security_groups_ids = [sec_dict[s]
1083 for s in sec_groups_names]
1084
1085 if security_groups_ids:
1086 create_port_body[
1087 'security_groups'] = security_groups_ids
1088 networks = create_kwargs.get('networks')
1089 else:
1090 net_client = self.network_client
1091 # If there are no networks passed to us we look up
1092 # for the tenant's private networks and create a port
1093 # if there is only one private network. The same behaviour
1094 # as we would expect when passing the call to the clients
1095 # with no networks
1096 if not networks:
1097 networks = net_client.list_networks(filters={
1098 'router:external': False})
1099 self.assertEqual(1, len(networks),
1100 "There is more than one"
1101 " network for the tenant")
1102 for net in networks:
1103 net_id = net['uuid']
1104 port = self._create_port(network_id=net_id,
1105 client=net_client,
1106 **create_port_body)
1107 ports.append({'port': port.id})
1108 if ports:
1109 create_kwargs['networks'] = ports
1110
1111 return super(NetworkScenarioTest, self).create_server(
1112 name=name, image=image, flavor=flavor,
1113 wait_on_boot=wait_on_boot, wait_on_delete=wait_on_delete,
1114 create_kwargs=create_kwargs)
1115
Yair Fried1fc32a12014-08-04 09:11:30 +03001116
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001117# power/provision states as of icehouse
1118class BaremetalPowerStates(object):
1119 """Possible power states of an Ironic node."""
1120 POWER_ON = 'power on'
1121 POWER_OFF = 'power off'
1122 REBOOT = 'rebooting'
1123 SUSPEND = 'suspended'
1124
1125
1126class BaremetalProvisionStates(object):
1127 """Possible provision states of an Ironic node."""
1128 NOSTATE = None
1129 INIT = 'initializing'
1130 ACTIVE = 'active'
1131 BUILDING = 'building'
1132 DEPLOYWAIT = 'wait call-back'
1133 DEPLOYING = 'deploying'
1134 DEPLOYFAIL = 'deploy failed'
1135 DEPLOYDONE = 'deploy complete'
1136 DELETING = 'deleting'
1137 DELETED = 'deleted'
1138 ERROR = 'error'
1139
1140
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001141class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001142
1143 credentials = ['primary', 'admin']
1144
Adam Gandelman4a48a602014-03-20 18:23:18 -07001145 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001146 def skip_checks(cls):
1147 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001148 if (not CONF.service_available.ironic or
1149 not CONF.baremetal.driver_enabled):
1150 msg = 'Ironic not available or Ironic compute driver not enabled'
1151 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001152
1153 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001154 def setup_clients(cls):
1155 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001156
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001157 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001158
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001159 @classmethod
1160 def resource_setup(cls):
1161 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001162 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001163 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001164
1165 def _node_state_timeout(self, node_id, state_attr,
1166 target_states, timeout=10, interval=1):
1167 if not isinstance(target_states, list):
1168 target_states = [target_states]
1169
1170 def check_state():
1171 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001172 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001173 return True
1174 return False
1175
1176 if not tempest.test.call_until_true(
1177 check_state, timeout, interval):
1178 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1179 (node_id, state_attr, target_states))
1180 raise exceptions.TimeoutException(msg)
1181
1182 def wait_provisioning_state(self, node_id, state, timeout):
1183 self._node_state_timeout(
1184 node_id=node_id, state_attr='provision_state',
1185 target_states=state, timeout=timeout)
1186
1187 def wait_power_state(self, node_id, state):
1188 self._node_state_timeout(
1189 node_id=node_id, state_attr='power_state',
1190 target_states=state, timeout=CONF.baremetal.power_timeout)
1191
1192 def wait_node(self, instance_id):
1193 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001194
Adam Gandelman4a48a602014-03-20 18:23:18 -07001195 def _get_node():
1196 node = None
1197 try:
1198 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001199 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001200 pass
1201 return node is not None
1202
1203 if not tempest.test.call_until_true(
1204 _get_node, CONF.baremetal.association_timeout, 1):
1205 msg = ('Timed out waiting to get Ironic node by instance id %s'
1206 % instance_id)
1207 raise exceptions.TimeoutException(msg)
1208
1209 def get_node(self, node_id=None, instance_id=None):
1210 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001211 _, body = self.baremetal_client.show_node(node_id)
1212 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001213 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001214 _, body = self.baremetal_client.show_node_by_instance_uuid(
1215 instance_id)
1216 if body['nodes']:
1217 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001218
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001219 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001220 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001221 _, body = self.baremetal_client.list_node_ports(node_uuid)
1222 for port in body['ports']:
1223 _, p = self.baremetal_client.show_port(port['uuid'])
1224 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001225 return ports
1226
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001227 def add_keypair(self):
1228 self.keypair = self.create_keypair()
1229
1230 def verify_connectivity(self, ip=None):
1231 if ip:
1232 dest = self.get_remote_client(ip)
1233 else:
1234 dest = self.get_remote_client(self.instance)
1235 dest.validate_authentication()
1236
1237 def boot_instance(self):
1238 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001239 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001240 }
1241 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001242 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001243
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001244 self.wait_node(self.instance['id'])
1245 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001246
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001247 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001248
1249 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001250 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001251 [BaremetalProvisionStates.DEPLOYWAIT,
1252 BaremetalProvisionStates.ACTIVE],
1253 timeout=15)
1254
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001255 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001256 BaremetalProvisionStates.ACTIVE,
1257 timeout=CONF.baremetal.active_timeout)
1258
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001259 self.servers_client.wait_for_server_status(self.instance['id'],
1260 'ACTIVE')
1261 self.node = self.get_node(instance_id=self.instance['id'])
David Kranz0fb14292015-02-11 15:55:20 -05001262 self.instance = self.servers_client.get_server(self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001263
1264 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001265 self.servers_client.delete_server(self.instance['id'])
1266 self.wait_power_state(self.node['uuid'],
1267 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001268 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001269 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001270 BaremetalProvisionStates.NOSTATE,
1271 timeout=CONF.baremetal.unprovision_timeout)
1272
Adam Gandelman4a48a602014-03-20 18:23:18 -07001273
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001274class EncryptionScenarioTest(ScenarioTest):
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001275 """
1276 Base class for encryption scenario tests
1277 """
1278
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001279 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001280
1281 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001282 def setup_clients(cls):
1283 super(EncryptionScenarioTest, cls).setup_clients()
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001284 cls.admin_volume_types_client = cls.os_adm.volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001285
1286 def _wait_for_volume_status(self, status):
1287 self.status_timeout(
1288 self.volume_client.volumes, self.volume.id, status)
1289
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001290 def nova_boot(self):
1291 self.keypair = self.create_keypair()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001292 create_kwargs = {'key_name': self.keypair['name']}
1293 self.server = self.create_server(image=self.image,
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001294 create_kwargs=create_kwargs)
1295
1296 def create_volume_type(self, client=None, name=None):
1297 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001298 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001299 if not name:
1300 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001301 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001302 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001303 body = client.create_volume_type(
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001304 randomized_name)
1305 self.assertIn('id', body)
1306 self.addCleanup(client.delete_volume_type, body['id'])
1307 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001308
1309 def create_encryption_type(self, client=None, type_id=None, provider=None,
1310 key_size=None, cipher=None,
1311 control_location=None):
1312 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001313 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001314 if not type_id:
1315 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001316 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001317 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001318 client.create_encryption_type(
1319 type_id, provider=provider, key_size=key_size, cipher=cipher,
1320 control_location=control_location)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001321
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001322
Chris Dent0d494112014-08-26 13:48:30 +01001323class SwiftScenarioTest(ScenarioTest):
1324 """
1325 Provide harness to do Swift scenario tests.
1326
1327 Subclasses implement the tests that use the methods provided by this
1328 class.
1329 """
1330
1331 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001332 def skip_checks(cls):
1333 super(SwiftScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001334 if not CONF.service_available.swift:
1335 skip_msg = ("%s skipped as swift is not available" %
1336 cls.__name__)
1337 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001338
1339 @classmethod
1340 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001341 cls.set_network_resources()
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001342 super(SwiftScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001343 operator_role = CONF.object_storage.operator_role
1344 if not cls.isolated_creds.is_role_available(operator_role):
1345 skip_msg = ("%s skipped because the configured credential provider"
1346 " is not able to provide credentials with the %s role "
1347 "assigned." % (cls.__name__, operator_role))
1348 raise cls.skipException(skip_msg)
1349 else:
1350 cls.os_operator = clients.Manager(
1351 cls.isolated_creds.get_creds_by_roles(
1352 [operator_role]))
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001353
1354 @classmethod
1355 def setup_clients(cls):
1356 super(SwiftScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001357 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001358 cls.account_client = cls.os_operator.account_client
1359 cls.container_client = cls.os_operator.container_client
1360 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001361
Chris Dentde456a12014-09-10 12:41:15 +01001362 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001363 """get swift status for our user account."""
1364 self.account_client.list_account_containers()
1365 LOG.debug('Swift status information obtained successfully')
1366
Chris Dentde456a12014-09-10 12:41:15 +01001367 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001368 name = container_name or data_utils.rand_name(
1369 'swift-scenario-container')
1370 self.container_client.create_container(name)
1371 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001372 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001373 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001374 self.addCleanup(self.delete_wrapper,
1375 self.container_client.delete_container,
1376 name)
Chris Dent0d494112014-08-26 13:48:30 +01001377 return name
1378
Chris Dentde456a12014-09-10 12:41:15 +01001379 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001380 self.container_client.delete_container(container_name)
1381 LOG.debug('Container %s deleted' % (container_name))
1382
Chris Dentde456a12014-09-10 12:41:15 +01001383 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001384 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1385 obj_data = data_utils.arbitrary_string()
1386 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001387 self.addCleanup(self.delete_wrapper,
1388 self.object_client.delete_object,
1389 container_name,
1390 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001391 return obj_name, obj_data
1392
Chris Dentde456a12014-09-10 12:41:15 +01001393 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001394 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001395 self.list_and_check_container_objects(container_name,
1396 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001397
Chris Dentde456a12014-09-10 12:41:15 +01001398 def list_and_check_container_objects(self, container_name,
1399 present_obj=None,
1400 not_present_obj=None):
Chris Dent0d494112014-08-26 13:48:30 +01001401 """
1402 List objects for a given container and assert which are present and
1403 which are not.
1404 """
Ghanshyam2a180b82014-06-16 13:54:22 +09001405 if present_obj is None:
1406 present_obj = []
1407 if not_present_obj is None:
1408 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001409 _, object_list = self.container_client.list_container_contents(
1410 container_name)
1411 if present_obj:
1412 for obj in present_obj:
1413 self.assertIn(obj, object_list)
1414 if not_present_obj:
1415 for obj in not_present_obj:
1416 self.assertNotIn(obj, object_list)
1417
Chris Dentde456a12014-09-10 12:41:15 +01001418 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001419 metadata_param = {'metadata_prefix': 'x-container-',
1420 'metadata': {'read': acl}}
1421 self.container_client.update_container_metadata(container_name,
1422 **metadata_param)
1423 resp, _ = self.container_client.list_container_metadata(container_name)
1424 self.assertEqual(resp['x-container-read'], acl)
1425
Chris Dentde456a12014-09-10 12:41:15 +01001426 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001427 _, obj = self.object_client.get_object(container_name, obj_name)
1428 self.assertEqual(obj, expected_data)