blob: d2c41f08f1eb4547bdab0294ec6d9d25c533c29b [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
Andrea Frittoli8283b4e2014-07-17 13:28:58 +010026from tempest.common import credentials
Rohan Kanade9ce97df2013-12-10 18:59:35 +053027from tempest.common import fixed_network
Masayuki Igawa4ded9f02014-02-17 15:05:59 +090028from tempest.common.utils.linux import remote_client
Matthew Treinish6c072292014-01-29 19:15:52 +000029from tempest import config
Giulio Fidente92f77192013-08-26 17:13:28 +020030from tempest import exceptions
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
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000043 def setup_credentials(cls):
44 super(ScenarioTest, cls).setup_credentials()
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 )
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000052
53 @classmethod
54 def setup_clients(cls):
55 super(ScenarioTest, cls).setup_clients()
Andrea Frittoli247058f2014-07-16 16:09:22 +010056 # Clients (in alphabetical order)
Adam Gandelmanc78c7572014-08-28 18:38:55 -070057 cls.flavors_client = cls.manager.flavors_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010058 cls.floating_ips_client = cls.manager.floating_ips_client
59 # Glance image client v1
60 cls.image_client = cls.manager.image_client
nithya-ganesan882595e2014-07-29 18:51:07 +000061 # Compute image client
62 cls.images_client = cls.manager.images_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010063 cls.keypairs_client = cls.manager.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010064 # Nova security groups client
65 cls.security_groups_client = cls.manager.security_groups_client
66 cls.servers_client = cls.manager.servers_client
67 cls.volumes_client = cls.manager.volumes_client
Joseph Lanouxeef192f2014-08-01 14:32:53 +000068 cls.snapshots_client = cls.manager.snapshots_client
Yair Fried1fc32a12014-08-04 09:11:30 +030069 cls.interface_client = cls.manager.interfaces_client
70 # Neutron network client
71 cls.network_client = cls.manager.network_client
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090072 # Heat client
73 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010074
75 @classmethod
Andrea Frittoli2e733b52014-07-16 14:12:11 +010076 def credentials(cls):
Andrea Frittoli8283b4e2014-07-17 13:28:58 +010077 return cls.isolated_creds.get_primary_creds()
Andrea Frittoli2e733b52014-07-16 14:12:11 +010078
Masayuki Igawaccd66592014-07-17 00:42:42 +090079 @classmethod
Yair Frieddb6c9e92014-08-06 08:53:13 +030080 def alt_credentials(cls):
Andrea Frittoli8283b4e2014-07-17 13:28:58 +010081 return cls.isolated_creds.get_alt_creds()
Yair Frieddb6c9e92014-08-06 08:53:13 +030082
83 @classmethod
Masayuki Igawaccd66592014-07-17 00:42:42 +090084 def admin_credentials(cls):
Andrea Frittoli8283b4e2014-07-17 13:28:58 +010085 try:
86 return cls.isolated_creds.get_admin_creds()
87 except NotImplementedError:
88 raise cls.skipException('Admin Credentials are not available')
Masayuki Igawaccd66592014-07-17 00:42:42 +090089
Andrea Frittoli247058f2014-07-16 16:09:22 +010090 # ## Methods to handle sync and async deletes
91
92 def setUp(self):
93 super(ScenarioTest, self).setUp()
94 self.cleanup_waits = []
95 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
96 # because scenario tests in the same test class should not share
97 # resources. If resources were shared between test cases then it
98 # should be a single scenario test instead of multiples.
99
100 # NOTE(yfried): this list is cleaned at the end of test_methods and
101 # not at the end of the class
102 self.addCleanup(self._wait_for_cleanups)
103
Yair Fried1fc32a12014-08-04 09:11:30 +0300104 def delete_wrapper(self, delete_thing, *args, **kwargs):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100105 """Ignores NotFound exceptions for delete operations.
106
Yair Fried1fc32a12014-08-04 09:11:30 +0300107 @param delete_thing: delete method of a resource. method will be
108 executed as delete_thing(*args, **kwargs)
109
Andrea Frittoli247058f2014-07-16 16:09:22 +0100110 """
111 try:
112 # Tempest clients return dicts, so there is no common delete
113 # method available. Using a callable instead
Yair Fried1fc32a12014-08-04 09:11:30 +0300114 delete_thing(*args, **kwargs)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900115 except lib_exc.NotFound:
Andrea Frittoli247058f2014-07-16 16:09:22 +0100116 # If the resource is already missing, mission accomplished.
117 pass
118
119 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +0900120 cleanup_callable, cleanup_args=None,
121 cleanup_kwargs=None, ignore_error=True):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700122 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100123
124 @param waiter_callable: callable to wait for the resource to delete
125 @param thing_id: the id of the resource to be cleaned-up
126 @param thing_id_param: the name of the id param in the waiter
127 @param cleanup_callable: method to load pass to self.addCleanup with
128 the following *cleanup_args, **cleanup_kwargs.
129 usually a delete method.
130 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900131 if cleanup_args is None:
132 cleanup_args = []
133 if cleanup_kwargs is None:
134 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100135 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
136 wait_dict = {
137 'waiter_callable': waiter_callable,
138 thing_id_param: thing_id
139 }
140 self.cleanup_waits.append(wait_dict)
141
142 def _wait_for_cleanups(self):
143 """To handle async delete actions, a list of waits is added
144 which will be iterated over as the last step of clearing the
145 cleanup queue. That way all the delete calls are made up front
146 and the tests won't succeed unless the deletes are eventually
147 successful. This is the same basic approach used in the api tests to
148 limit cleanup execution time except here it is multi-resource,
149 because of the nature of the scenario tests.
150 """
151 for wait in self.cleanup_waits:
152 waiter_callable = wait.pop('waiter_callable')
153 waiter_callable(**wait)
154
155 # ## Test functions library
156 #
157 # The create_[resource] functions only return body and discard the
158 # resp part which is not used in scenario tests
159
Yair Frieddb6c9e92014-08-06 08:53:13 +0300160 def create_keypair(self, client=None):
161 if not client:
162 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100163 name = data_utils.rand_name(self.__class__.__name__)
164 # We don't need to create a keypair by pubkey in scenario
David Kranz173f0e02015-02-06 13:47:57 -0500165 body = client.create_keypair(name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300166 self.addCleanup(client.delete_keypair, name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100167 return body
168
169 def create_server(self, name=None, image=None, flavor=None,
170 wait_on_boot=True, wait_on_delete=True,
Ghanshyam2a180b82014-06-16 13:54:22 +0900171 create_kwargs=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100172 """Creates VM instance.
173
174 @param image: image from which to create the instance
175 @param wait_on_boot: wait for status ACTIVE before continue
176 @param wait_on_delete: force synchronous delete on cleanup
177 @param create_kwargs: additional details for instance creation
178 @return: server dict
179 """
180 if name is None:
181 name = data_utils.rand_name(self.__class__.__name__)
182 if image is None:
183 image = CONF.compute.image_ref
184 if flavor is None:
185 flavor = CONF.compute.flavor_ref
Ghanshyam2a180b82014-06-16 13:54:22 +0900186 if create_kwargs is None:
187 create_kwargs = {}
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530188 network = self.get_tenant_network()
Matthew Treinish4bbc1992015-04-07 11:13:40 -0400189 create_kwargs = fixed_network.set_networks_kwarg(network,
190 create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100191
Andrea Frittoli247058f2014-07-16 16:09:22 +0100192 LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
193 name, image, flavor)
David Kranz0fb14292015-02-11 15:55:20 -0500194 server = self.servers_client.create_server(name, image, flavor,
195 **create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100196 if wait_on_delete:
197 self.addCleanup(self.servers_client.wait_for_server_termination,
198 server['id'])
199 self.addCleanup_with_wait(
200 waiter_callable=self.servers_client.wait_for_server_termination,
201 thing_id=server['id'], thing_id_param='server_id',
202 cleanup_callable=self.delete_wrapper,
203 cleanup_args=[self.servers_client.delete_server, server['id']])
204 if wait_on_boot:
205 self.servers_client.wait_for_server_status(server_id=server['id'],
206 status='ACTIVE')
207 # The instance retrieved on creation is missing network
208 # details, necessitating retrieval after it becomes active to
209 # ensure correct details.
David Kranz0fb14292015-02-11 15:55:20 -0500210 server = self.servers_client.get_server(server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100211 self.assertEqual(server['name'], name)
212 return server
213
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100214 def create_volume(self, size=None, name=None, snapshot_id=None,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100215 imageRef=None, volume_type=None, wait_on_delete=True):
216 if name is None:
217 name = data_utils.rand_name(self.__class__.__name__)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000218 volume = self.volumes_client.create_volume(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100219 size=size, display_name=name, snapshot_id=snapshot_id,
220 imageRef=imageRef, volume_type=volume_type)
Matt Riedemanne85c2702014-09-10 11:50:13 -0700221
Andrea Frittoli247058f2014-07-16 16:09:22 +0100222 if wait_on_delete:
223 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
224 volume['id'])
Matt Riedemanne85c2702014-09-10 11:50:13 -0700225 self.addCleanup(self.delete_wrapper,
226 self.volumes_client.delete_volume, volume['id'])
227 else:
228 self.addCleanup_with_wait(
229 waiter_callable=self.volumes_client.wait_for_resource_deletion,
230 thing_id=volume['id'], thing_id_param='id',
231 cleanup_callable=self.delete_wrapper,
232 cleanup_args=[self.volumes_client.delete_volume, volume['id']])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100233
234 self.assertEqual(name, volume['display_name'])
235 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
236 # The volume retrieved on creation has a non-up-to-date status.
237 # Retrieval after it becomes active ensures correct details.
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000238 volume = self.volumes_client.show_volume(volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100239 return volume
240
Yair Fried1fc32a12014-08-04 09:11:30 +0300241 def _create_loginable_secgroup_rule(self, secgroup_id=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100242 _client = self.security_groups_client
243 if secgroup_id is None:
David Kranz9964b4e2015-02-06 15:45:29 -0500244 sgs = _client.list_security_groups()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100245 for sg in sgs:
246 if sg['name'] == 'default':
247 secgroup_id = sg['id']
248
249 # These rules are intended to permit inbound ssh and icmp
250 # traffic from all sources, so no group_id is provided.
251 # Setting a group_id would only permit traffic from ports
252 # belonging to the same security group.
253 rulesets = [
254 {
255 # ssh
256 'ip_proto': 'tcp',
257 'from_port': 22,
258 'to_port': 22,
259 'cidr': '0.0.0.0/0',
260 },
261 {
262 # ping
263 'ip_proto': 'icmp',
264 'from_port': -1,
265 'to_port': -1,
266 'cidr': '0.0.0.0/0',
267 }
268 ]
269 rules = list()
270 for ruleset in rulesets:
David Kranz9964b4e2015-02-06 15:45:29 -0500271 sg_rule = _client.create_security_group_rule(secgroup_id,
272 **ruleset)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100273 self.addCleanup(self.delete_wrapper,
274 _client.delete_security_group_rule,
275 sg_rule['id'])
276 rules.append(sg_rule)
277 return rules
278
Yair Fried1fc32a12014-08-04 09:11:30 +0300279 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100280 # Create security group
281 sg_name = data_utils.rand_name(self.__class__.__name__)
282 sg_desc = sg_name + " description"
David Kranz9964b4e2015-02-06 15:45:29 -0500283 secgroup = self.security_groups_client.create_security_group(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100284 sg_name, sg_desc)
285 self.assertEqual(secgroup['name'], sg_name)
286 self.assertEqual(secgroup['description'], sg_desc)
287 self.addCleanup(self.delete_wrapper,
288 self.security_groups_client.delete_security_group,
289 secgroup['id'])
290
291 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300292 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100293
294 return secgroup
295
JordanP3fe2dc32014-11-17 13:06:01 +0100296 def get_remote_client(self, server_or_ip, username=None, private_key=None,
297 log_console_of_servers=None):
298 """Get a SSH client to a remote server
299
300 @param server_or_ip a server object as returned by Tempest compute
301 client or an IP address to connect to
302 @param username name of the Linux account on the remote server
303 @param private_key the SSH private key to use
304 @param log_console_of_servers a list of server objects. Each server
305 in the list will have its console printed in the logs in case the
306 SSH connection failed to be established
307 @return a RemoteClient object
308 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100309 if isinstance(server_or_ip, six.string_types):
310 ip = server_or_ip
311 else:
Andrew Boik4a3daf12015-03-27 01:59:31 -0400312 addrs = server_or_ip['addresses'][CONF.compute.network_for_ssh]
313 try:
314 ip = (addr['addr'] for addr in addrs if
315 netaddr.valid_ipv4(addr['addr'])).next()
316 except StopIteration:
317 raise lib_exc.NotFound("No IPv4 addresses to use for SSH to "
318 "remote server.")
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700319
Andrea Frittoli247058f2014-07-16 16:09:22 +0100320 if username is None:
321 username = CONF.scenario.ssh_user
322 if private_key is None:
323 private_key = self.keypair['private_key']
324 linux_client = remote_client.RemoteClient(ip, username,
325 pkey=private_key)
326 try:
327 linux_client.validate_authentication()
JordanP3fe2dc32014-11-17 13:06:01 +0100328 except Exception:
329 LOG.exception('Initializing SSH connection to %s failed' % ip)
JordanP3fe2dc32014-11-17 13:06:01 +0100330 # If we don't explicitely set for which servers we want to
331 # log the console output then all the servers will be logged.
332 # See the definition of _log_console_output()
333 self._log_console_output(log_console_of_servers)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100334 raise
335
336 return linux_client
337
Ghanshyam2a180b82014-06-16 13:54:22 +0900338 def _image_create(self, name, fmt, path, properties=None):
339 if properties is None:
340 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100341 name = data_utils.rand_name('%s-' % name)
342 image_file = open(path, 'rb')
343 self.addCleanup(image_file.close)
344 params = {
345 'name': name,
346 'container_format': fmt,
347 'disk_format': fmt,
348 'is_public': 'False',
349 }
350 params.update(properties)
David Kranz34f18782015-01-06 13:43:55 -0500351 image = self.image_client.create_image(**params)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100352 self.addCleanup(self.image_client.delete_image, image['id'])
353 self.assertEqual("queued", image['status'])
354 self.image_client.update_image(image['id'], data=image_file)
355 return image['id']
356
357 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300358 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100359 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
360 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
361 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300362 img_container_format = CONF.scenario.img_container_format
363 img_disk_format = CONF.scenario.img_disk_format
364 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
365 "ami: %s, ari: %s, aki: %s" %
366 (img_path, img_container_format, img_disk_format,
367 ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100368 try:
369 self.image = self._image_create('scenario-img',
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300370 img_container_format,
371 img_path,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100372 properties={'disk_format':
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300373 img_disk_format})
Andrea Frittoli247058f2014-07-16 16:09:22 +0100374 except IOError:
375 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
376 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
377 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
378 properties = {
379 'properties': {'kernel_id': kernel, 'ramdisk_id': ramdisk}
380 }
381 self.image = self._image_create('scenario-ami', 'ami',
382 path=ami_img_path,
383 properties=properties)
384 LOG.debug("image:%s" % self.image)
385
386 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400387 if not CONF.compute_feature_enabled.console_output:
388 LOG.debug('Console output not supported, cannot log')
389 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100390 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500391 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100392 servers = servers['servers']
393 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500394 console_output = self.servers_client.get_console_output(
David Kranzae99b9a2015-02-16 13:37:01 -0500395 server['id'], length=None).data
396 LOG.debug('Console output for %s\nbody=\n%s',
397 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100398
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000399 def _log_net_info(self, exc):
400 # network debug is called as part of ssh init
401 if not isinstance(exc, exceptions.SSHTimeout):
402 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000403
nithya-ganesan882595e2014-07-29 18:51:07 +0000404 def create_server_snapshot(self, server, name=None):
405 # Glance client
406 _image_client = self.image_client
407 # Compute client
408 _images_client = self.images_client
409 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000410 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000411 LOG.debug("Creating a snapshot image for server: %s", server['name'])
David Kranza5299eb2015-01-15 17:24:05 -0500412 image = _images_client.create_image(server['id'], name)
413 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000414 _image_client.wait_for_image_status(image_id, 'active')
415 self.addCleanup_with_wait(
416 waiter_callable=_image_client.wait_for_resource_deletion,
417 thing_id=image_id, thing_id_param='id',
418 cleanup_callable=self.delete_wrapper,
419 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500420 snapshot_image = _image_client.get_image_meta(image_id)
nithya-ganesan882595e2014-07-29 18:51:07 +0000421 image_name = snapshot_image['name']
422 self.assertEqual(name, image_name)
423 LOG.debug("Created snapshot image %s for server %s",
424 image_name, server['name'])
425 return snapshot_image
426
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900427 def nova_volume_attach(self):
428 # TODO(andreaf) Device should be here CONF.compute.volume_device_name
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000429 volume = self.servers_client.attach_volume(
David Kranz3ebc7212015-02-10 12:19:19 -0500430 self.server['id'], self.volume['id'], '/dev/vdb')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900431 self.assertEqual(self.volume['id'], volume['id'])
432 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
433 # Refresh the volume after the attachment
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000434 self.volume = self.volumes_client.show_volume(volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900435
436 def nova_volume_detach(self):
437 self.servers_client.detach_volume(self.server['id'], self.volume['id'])
438 self.volumes_client.wait_for_volume_status(self.volume['id'],
439 'available')
440
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000441 volume = self.volumes_client.show_volume(self.volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900442 self.assertEqual('available', volume['status'])
443
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700444 def rebuild_server(self, server_id, image=None,
445 preserve_ephemeral=False, wait=True,
446 rebuild_kwargs=None):
447 if image is None:
448 image = CONF.compute.image_ref
449
450 rebuild_kwargs = rebuild_kwargs or {}
451
452 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
453 server_id, image, preserve_ephemeral)
454 self.servers_client.rebuild(server_id=server_id, image_ref=image,
455 preserve_ephemeral=preserve_ephemeral,
456 **rebuild_kwargs)
457 if wait:
458 self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
459
Steven Hardyda2a8352014-10-02 12:52:20 +0100460 def ping_ip_address(self, ip_address, should_succeed=True,
461 ping_timeout=None):
462 timeout = ping_timeout or CONF.compute.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700463 cmd = ['ping', '-c1', '-w1', ip_address]
464
465 def ping():
466 proc = subprocess.Popen(cmd,
467 stdout=subprocess.PIPE,
468 stderr=subprocess.PIPE)
469 proc.communicate()
470 return (proc.returncode == 0) == should_succeed
471
Steven Hardyda2a8352014-10-02 12:52:20 +0100472 return tempest.test.call_until_true(ping, timeout, 1)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700473
Yair Friedae0e73d2014-11-24 11:56:26 +0200474 def check_vm_connectivity(self, ip_address,
475 username=None,
476 private_key=None,
477 should_connect=True):
478 """
479 :param ip_address: server to test against
480 :param username: server's ssh username
481 :param private_key: server's ssh private key to be used
482 :param should_connect: True/False indicates positive/negative test
483 positive - attempt ping and ssh
484 negative - attempt ping and fail if succeed
485
486 :raises: AssertError if the result of the connectivity check does
487 not match the value of the should_connect param
488 """
489 if should_connect:
490 msg = "Timed out waiting for %s to become reachable" % ip_address
491 else:
492 msg = "ip address %s is reachable" % ip_address
493 self.assertTrue(self.ping_ip_address(ip_address,
494 should_succeed=should_connect),
495 msg=msg)
496 if should_connect:
497 # no need to check ssh for negative connectivity
498 self.get_remote_client(ip_address, username, private_key)
499
500 def check_public_network_connectivity(self, ip_address, username,
501 private_key, should_connect=True,
502 msg=None, servers=None):
503 # The target login is assumed to have been configured for
504 # key-based authentication by cloud-init.
505 LOG.debug('checking network connections to IP %s with user: %s' %
506 (ip_address, username))
507 try:
508 self.check_vm_connectivity(ip_address,
509 username,
510 private_key,
511 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500512 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200513 ex_msg = 'Public network connectivity check failed'
514 if msg:
515 ex_msg += ": " + msg
516 LOG.exception(ex_msg)
517 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200518 raise
519
520 def create_floating_ip(self, thing, pool_name=None):
521 """Creates a floating IP and associates to a server using
522 Nova clients
523 """
524
David Kranze4e3b412015-02-10 10:50:42 -0500525 floating_ip = self.floating_ips_client.create_floating_ip(pool_name)
Yair Friedae0e73d2014-11-24 11:56:26 +0200526 self.addCleanup(self.delete_wrapper,
527 self.floating_ips_client.delete_floating_ip,
528 floating_ip['id'])
529 self.floating_ips_client.associate_floating_ip_to_server(
530 floating_ip['ip'], thing['id'])
531 return floating_ip
532
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100533
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100534class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300535 """Base class for network scenario tests.
536 This class provide helpers for network scenario tests, using the neutron
537 API. Helpers from ancestor which use the nova network API are overridden
538 with the neutron API.
539
540 This Class also enforces using Neutron instead of novanetwork.
541 Subclassed tests will be skipped if Neutron is not enabled
542
543 """
544
545 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000546 def skip_checks(cls):
547 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100548 if not CONF.service_available.neutron:
549 raise cls.skipException('Neutron not available')
David Kranz4cc852b2015-03-09 14:57:11 -0400550 if not credentials.is_admin_available():
551 msg = ("Missing Identity Admin API credentials in configuration.")
552 raise cls.skipException(msg)
553
554 @classmethod
555 def setup_credentials(cls):
556 super(NetworkScenarioTest, cls).setup_credentials()
557 cls.admin_manager = clients.Manager(cls.admin_credentials())
Yair Fried1fc32a12014-08-04 09:11:30 +0300558
559 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100560 def resource_setup(cls):
561 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300562 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300563
Yair Frieddb6c9e92014-08-06 08:53:13 +0300564 def _create_network(self, client=None, tenant_id=None,
565 namestart='network-smoke-'):
566 if not client:
567 client = self.network_client
568 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000569 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300570 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500571 result = client.create_network(name=name, tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300572 network = net_resources.DeletableNetwork(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300573 **result['network'])
574 self.assertEqual(network.name, name)
575 self.addCleanup(self.delete_wrapper, network.delete)
576 return network
577
578 def _list_networks(self, *args, **kwargs):
579 """List networks using admin creds """
580 return self._admin_lister('networks')(*args, **kwargs)
581
582 def _list_subnets(self, *args, **kwargs):
583 """List subnets using admin creds """
584 return self._admin_lister('subnets')(*args, **kwargs)
585
586 def _list_routers(self, *args, **kwargs):
587 """List routers using admin creds """
588 return self._admin_lister('routers')(*args, **kwargs)
589
590 def _list_ports(self, *args, **kwargs):
591 """List ports using admin creds """
592 return self._admin_lister('ports')(*args, **kwargs)
593
594 def _admin_lister(self, resource_type):
595 def temp(*args, **kwargs):
596 temp_method = self.admin_manager.network_client.__getattr__(
597 'list_%s' % resource_type)
David Kranz34e88122014-12-11 15:24:05 -0500598 resource_list = temp_method(*args, **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300599 return resource_list[resource_type]
600 return temp
601
Yair Frieddb6c9e92014-08-06 08:53:13 +0300602 def _create_subnet(self, network, client=None, namestart='subnet-smoke',
603 **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300604 """
605 Create a subnet for the given network within the cidr block
606 configured for tenant networks.
607 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300608 if not client:
609 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300610
611 def cidr_in_use(cidr, tenant_id):
612 """
613 :return True if subnet with cidr already exist in tenant
614 False else
615 """
616 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
617 return len(cidr_in_use) != 0
618
Kirill Shileev14113572014-11-21 16:58:02 +0300619 ip_version = kwargs.pop('ip_version', 4)
620
621 if ip_version == 6:
622 tenant_cidr = netaddr.IPNetwork(
623 CONF.network.tenant_network_v6_cidr)
624 num_bits = CONF.network.tenant_network_v6_mask_bits
625 else:
626 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
627 num_bits = CONF.network.tenant_network_mask_bits
628
Yair Fried1fc32a12014-08-04 09:11:30 +0300629 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300630 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300631 # Repeatedly attempt subnet creation with sequential cidr
632 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300633 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300634 str_cidr = str(subnet_cidr)
635 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
636 continue
637
638 subnet = dict(
639 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300640 network_id=network.id,
641 tenant_id=network.tenant_id,
642 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300643 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300644 **kwargs
645 )
646 try:
David Kranz34e88122014-12-11 15:24:05 -0500647 result = client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300648 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900649 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300650 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
651 if not is_overlapping_cidr:
652 raise
653 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300654 subnet = net_resources.DeletableSubnet(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300655 **result['subnet'])
656 self.assertEqual(subnet.cidr, str_cidr)
657 self.addCleanup(self.delete_wrapper, subnet.delete)
658 return subnet
659
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200660 def _create_port(self, network_id, client=None, namestart='port-quotatest',
661 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300662 if not client:
663 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300664 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500665 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300666 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200667 network_id=network_id,
668 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300669 self.assertIsNotNone(result, 'Unable to allocate port')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300670 port = net_resources.DeletablePort(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300671 **result['port'])
672 self.addCleanup(self.delete_wrapper, port.delete)
673 return port
674
Kirill Shileev14113572014-11-21 16:58:02 +0300675 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300676 ports = self._list_ports(device_id=server['id'],
677 fixed_ip=ip_addr)
678 self.assertEqual(len(ports), 1,
679 "Unable to determine which port to target.")
Kirill Shileev14113572014-11-21 16:58:02 +0300680 # it might happen here that this port has more then one ip address
681 # as in case of dual stack- when this port is created on 2 subnets
682 for ip46 in ports[0]['fixed_ips']:
683 ip = ip46['ip_address']
684 if netaddr.valid_ipv4(ip):
685 return ports[0]['id'], ip
Yair Fried1fc32a12014-08-04 09:11:30 +0300686
David Shrewsbury9bac3662014-08-07 15:07:01 -0400687 def _get_network_by_name(self, network_name):
688 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700689 self.assertNotEqual(len(net), 0,
690 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300691 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400692
Yair Friedae0e73d2014-11-24 11:56:26 +0200693 def create_floating_ip(self, thing, external_network_id=None,
694 port_id=None, client=None):
695 """Creates a floating IP and associates to a resource/port using
696 Neutron client
697 """
698 if not external_network_id:
699 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300700 if not client:
701 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300702 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300703 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
704 else:
705 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500706 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300707 floating_network_id=external_network_id,
708 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300709 tenant_id=thing['tenant_id'],
710 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300711 )
712 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300713 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300714 **result['floatingip'])
715 self.addCleanup(self.delete_wrapper, floating_ip.delete)
716 return floating_ip
717
718 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300719 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300720 floating_ip.update(port_id=port_id)
721 self.assertEqual(port_id, floating_ip.port_id)
722 return floating_ip
723
724 def _disassociate_floating_ip(self, floating_ip):
725 """
726 :param floating_ip: type DeletableFloatingIp
727 """
728 floating_ip.update(port_id=None)
729 self.assertIsNone(floating_ip.port_id)
730 return floating_ip
731
Yair Fried45f92952014-06-26 05:19:19 +0300732 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000733 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300734
735 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
736 to check status
737 :param status: target status
738 :raises: AssertionError if status doesn't match
739 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000740 def refresh():
741 floating_ip.refresh()
742 return status == floating_ip.status
743
744 tempest.test.call_until_true(refresh,
745 CONF.network.build_timeout,
746 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300747 self.assertEqual(status, floating_ip.status,
748 message="FloatingIP: {fp} is at status: {cst}. "
749 "failed to reach status: {st}"
750 .format(fp=floating_ip, cst=floating_ip.status,
751 st=status))
752 LOG.info("FloatingIP: {fp} is at status: {st}"
753 .format(fp=floating_ip, st=status))
754
Yair Fried1fc32a12014-08-04 09:11:30 +0300755 def _check_tenant_network_connectivity(self, server,
756 username,
757 private_key,
758 should_connect=True,
759 servers_for_debug=None):
760 if not CONF.network.tenant_networks_reachable:
761 msg = 'Tenant networks not configured to be reachable.'
762 LOG.info(msg)
763 return
764 # The target login is assumed to have been configured for
765 # key-based authentication by cloud-init.
766 try:
ghanshyam807211c2014-12-18 13:21:22 +0900767 for net_name, ip_addresses in server['addresses'].iteritems():
Yair Fried1fc32a12014-08-04 09:11:30 +0300768 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900769 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200770 username,
771 private_key,
772 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300773 except Exception as e:
774 LOG.exception('Tenant network connectivity check failed')
775 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000776 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300777 raise
778
779 def _check_remote_connectivity(self, source, dest, should_succeed=True):
780 """
781 check ping server via source ssh connection
782
783 :param source: RemoteClient: an ssh connection from which to ping
784 :param dest: and IP to ping against
785 :param should_succeed: boolean should ping succeed or not
786 :returns: boolean -- should_succeed == ping
787 :returns: ping is false if ping failed
788 """
789 def ping_remote():
790 try:
791 source.ping_host(dest)
792 except exceptions.SSHExecCommandFailed:
793 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
794 % (dest, source.ssh_client.host))
795 return not should_succeed
796 return should_succeed
797
798 return tempest.test.call_until_true(ping_remote,
799 CONF.compute.ping_timeout,
800 1)
801
Yair Frieddb6c9e92014-08-06 08:53:13 +0300802 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300803 namestart='secgroup-smoke'):
804 if client is None:
805 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300806 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000807 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300808 secgroup = self._create_empty_security_group(namestart=namestart,
809 client=client,
810 tenant_id=tenant_id)
811
812 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900813 rules = self._create_loginable_secgroup_rule(client=client,
814 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300815 for rule in rules:
816 self.assertEqual(tenant_id, rule.tenant_id)
817 self.assertEqual(secgroup.id, rule.security_group_id)
818 return secgroup
819
Yair Frieddb6c9e92014-08-06 08:53:13 +0300820 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300821 namestart='secgroup-smoke'):
822 """Create a security group without rules.
823
824 Default rules will be created:
825 - IPv4 egress to any
826 - IPv6 egress to any
827
828 :param tenant_id: secgroup will be created in this tenant
829 :returns: DeletableSecurityGroup -- containing the secgroup created
830 """
831 if client is None:
832 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300833 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000834 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300835 sg_name = data_utils.rand_name(namestart)
836 sg_desc = sg_name + " description"
837 sg_dict = dict(name=sg_name,
838 description=sg_desc)
839 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500840 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300841 secgroup = net_resources.DeletableSecurityGroup(
842 client=client,
843 **result['security_group']
844 )
845 self.assertEqual(secgroup.name, sg_name)
846 self.assertEqual(tenant_id, secgroup.tenant_id)
847 self.assertEqual(secgroup.description, sg_desc)
848 self.addCleanup(self.delete_wrapper, secgroup.delete)
849 return secgroup
850
Yair Frieddb6c9e92014-08-06 08:53:13 +0300851 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300852 """Get default secgroup for given tenant_id.
853
854 :returns: DeletableSecurityGroup -- default secgroup for given tenant
855 """
856 if client is None:
857 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300858 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000859 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300860 sgs = [
861 sg for sg in client.list_security_groups().values()[0]
862 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
863 ]
864 msg = "No default security group for tenant %s." % (tenant_id)
865 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300866 return net_resources.DeletableSecurityGroup(client=client,
867 **sgs[0])
868
Yair Frieddb6c9e92014-08-06 08:53:13 +0300869 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300870 tenant_id=None, **kwargs):
871 """Create a rule from a dictionary of rule parameters.
872
873 Create a rule in a secgroup. if secgroup not defined will search for
874 default secgroup in tenant_id.
875
876 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300877 :param tenant_id: if secgroup not passed -- the tenant in which to
878 search for default secgroup
879 :param kwargs: a dictionary containing rule parameters:
880 for example, to allow incoming ssh:
881 rule = {
882 direction: 'ingress'
883 protocol:'tcp',
884 port_range_min: 22,
885 port_range_max: 22
886 }
887 """
888 if client is None:
889 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300890 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000891 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300892 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300893 secgroup = self._default_security_group(client=client,
894 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300895
896 ruleset = dict(security_group_id=secgroup.id,
897 tenant_id=secgroup.tenant_id)
898 ruleset.update(kwargs)
899
David Kranz34e88122014-12-11 15:24:05 -0500900 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300901 sg_rule = net_resources.DeletableSecurityGroupRule(
902 client=client,
903 **sg_rule['security_group_rule']
904 )
905 self.addCleanup(self.delete_wrapper, sg_rule.delete)
906 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
907 self.assertEqual(secgroup.id, sg_rule.security_group_id)
908
909 return sg_rule
910
911 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
912 """These rules are intended to permit inbound ssh and icmp
913 traffic from all sources, so no group_id is provided.
914 Setting a group_id would only permit traffic from ports
915 belonging to the same security group.
916 """
917
918 if client is None:
919 client = self.network_client
920 rules = []
921 rulesets = [
922 dict(
923 # ssh
924 protocol='tcp',
925 port_range_min=22,
926 port_range_max=22,
927 ),
928 dict(
929 # ping
930 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +0100931 ),
932 dict(
933 # ipv6-icmp for ping6
934 protocol='icmp',
935 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +0300936 )
937 ]
938 for ruleset in rulesets:
939 for r_direction in ['ingress', 'egress']:
940 ruleset['direction'] = r_direction
941 try:
942 sg_rule = self._create_security_group_rule(
943 client=client, secgroup=secgroup, **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +0900944 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +0300945 # if rule already exist - skip rule and continue
946 msg = 'Security group rule already exists'
947 if msg not in ex._error_string:
948 raise ex
949 else:
950 self.assertEqual(r_direction, sg_rule.direction)
951 rules.append(sg_rule)
952
953 return rules
954
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500955 def _create_pool(self, lb_method, protocol, subnet_id):
956 """Wrapper utility that returns a test pool."""
957 client = self.network_client
958 name = data_utils.rand_name('pool')
David Kranz34e88122014-12-11 15:24:05 -0500959 resp_pool = client.create_pool(protocol=protocol, name=name,
960 subnet_id=subnet_id,
961 lb_method=lb_method)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500962 pool = net_resources.DeletablePool(client=client, **resp_pool['pool'])
963 self.assertEqual(pool['name'], name)
964 self.addCleanup(self.delete_wrapper, pool.delete)
965 return pool
966
967 def _create_member(self, address, protocol_port, pool_id):
968 """Wrapper utility that returns a test member."""
969 client = self.network_client
David Kranz34e88122014-12-11 15:24:05 -0500970 resp_member = client.create_member(protocol_port=protocol_port,
971 pool_id=pool_id,
972 address=address)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500973 member = net_resources.DeletableMember(client=client,
974 **resp_member['member'])
975 self.addCleanup(self.delete_wrapper, member.delete)
976 return member
977
978 def _create_vip(self, protocol, protocol_port, subnet_id, pool_id):
979 """Wrapper utility that returns a test vip."""
980 client = self.network_client
981 name = data_utils.rand_name('vip')
David Kranz34e88122014-12-11 15:24:05 -0500982 resp_vip = client.create_vip(protocol=protocol, name=name,
983 subnet_id=subnet_id, pool_id=pool_id,
984 protocol_port=protocol_port)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500985 vip = net_resources.DeletableVip(client=client, **resp_vip['vip'])
986 self.assertEqual(vip['name'], name)
987 self.addCleanup(self.delete_wrapper, vip.delete)
988 return vip
989
Yair Fried1fc32a12014-08-04 09:11:30 +0300990 def _ssh_to_server(self, server, private_key):
991 ssh_login = CONF.compute.image_ssh_user
992 return self.get_remote_client(server,
993 username=ssh_login,
994 private_key=private_key)
995
Yair Frieddb6c9e92014-08-06 08:53:13 +0300996 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300997 """Retrieve a router for the given tenant id.
998
999 If a public router has been configured, it will be returned.
1000
1001 If a public router has not been configured, but a public
1002 network has, a tenant router will be created and returned that
1003 routes traffic to the public network.
1004 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001005 if not client:
1006 client = self.network_client
1007 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001008 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001009 router_id = CONF.network.public_router_id
1010 network_id = CONF.network.public_network_id
1011 if router_id:
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +04001012 resp, body = client.show_router(router_id)
1013 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001014 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001015 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001016 router.set_gateway(network_id)
1017 return router
1018 else:
1019 raise Exception("Neither of 'public_router_id' or "
1020 "'public_network_id' has been defined.")
1021
Yair Frieddb6c9e92014-08-06 08:53:13 +03001022 def _create_router(self, client=None, tenant_id=None,
1023 namestart='router-smoke'):
1024 if not client:
1025 client = self.network_client
1026 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001027 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001028 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001029 result = client.create_router(name=name,
1030 admin_state_up=True,
1031 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001032 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001033 **result['router'])
1034 self.assertEqual(router.name, name)
1035 self.addCleanup(self.delete_wrapper, router.delete)
1036 return router
1037
Alok Maurya6384bbb2014-07-13 06:44:29 -07001038 def _update_router_admin_state(self, router, admin_state_up):
1039 router.update(admin_state_up=admin_state_up)
1040 self.assertEqual(admin_state_up, router.admin_state_up)
1041
Yair Fried413bf2d2014-11-19 17:07:11 +02001042 def create_networks(self, client=None, tenant_id=None,
1043 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001044 """Create a network with a subnet connected to a router.
1045
David Shrewsbury9bac3662014-08-07 15:07:01 -04001046 The baremetal driver is a special case since all nodes are
1047 on the same shared network.
1048
Yair Fried413bf2d2014-11-19 17:07:11 +02001049 :param client: network client to create resources with.
1050 :param tenant_id: id of tenant to create resources in.
1051 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001052 :returns: network, subnet, router
1053 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001054 if CONF.baremetal.driver_enabled:
1055 # NOTE(Shrews): This exception is for environments where tenant
1056 # credential isolation is available, but network separation is
1057 # not (the current baremetal case). Likely can be removed when
1058 # test account mgmt is reworked:
1059 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001060 if not CONF.compute.fixed_network_name:
1061 m = 'fixed_network_name must be specified in config'
1062 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001063 network = self._get_network_by_name(
1064 CONF.compute.fixed_network_name)
1065 router = None
1066 subnet = None
1067 else:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001068 network = self._create_network(client=client, tenant_id=tenant_id)
1069 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001070
1071 subnet_kwargs = dict(network=network, client=client)
1072 # use explicit check because empty list is a valid option
1073 if dns_nameservers is not None:
1074 subnet_kwargs['dns_nameservers'] = dns_nameservers
1075 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001076 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001077 return network, subnet, router
1078
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001079 def create_server(self, name=None, image=None, flavor=None,
1080 wait_on_boot=True, wait_on_delete=True,
1081 create_kwargs=None):
1082 vnic_type = CONF.network.port_vnic_type
1083
1084 # If vnic_type is configured create port for
1085 # every network
1086 if vnic_type:
1087 ports = []
1088 networks = []
1089 create_port_body = {'binding:vnic_type': vnic_type,
1090 'namestart': 'port-smoke'}
1091 if create_kwargs:
1092 net_client = create_kwargs.get("network_client",
1093 self.network_client)
1094
1095 # Convert security group names to security group ids
1096 # to pass to create_port
1097 if create_kwargs.get('security_groups'):
1098 security_groups = net_client.list_security_groups().get(
1099 'security_groups')
1100 sec_dict = dict([(s['name'], s['id'])
1101 for s in security_groups])
1102
1103 sec_groups_names = [s['name'] for s in create_kwargs[
1104 'security_groups']]
1105 security_groups_ids = [sec_dict[s]
1106 for s in sec_groups_names]
1107
1108 if security_groups_ids:
1109 create_port_body[
1110 'security_groups'] = security_groups_ids
1111 networks = create_kwargs.get('networks')
1112 else:
1113 net_client = self.network_client
1114 # If there are no networks passed to us we look up
1115 # for the tenant's private networks and create a port
1116 # if there is only one private network. The same behaviour
1117 # as we would expect when passing the call to the clients
1118 # with no networks
1119 if not networks:
1120 networks = net_client.list_networks(filters={
1121 'router:external': False})
1122 self.assertEqual(1, len(networks),
1123 "There is more than one"
1124 " network for the tenant")
1125 for net in networks:
1126 net_id = net['uuid']
1127 port = self._create_port(network_id=net_id,
1128 client=net_client,
1129 **create_port_body)
1130 ports.append({'port': port.id})
1131 if ports:
1132 create_kwargs['networks'] = ports
1133
1134 return super(NetworkScenarioTest, self).create_server(
1135 name=name, image=image, flavor=flavor,
1136 wait_on_boot=wait_on_boot, wait_on_delete=wait_on_delete,
1137 create_kwargs=create_kwargs)
1138
Yair Fried1fc32a12014-08-04 09:11:30 +03001139
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001140# power/provision states as of icehouse
1141class BaremetalPowerStates(object):
1142 """Possible power states of an Ironic node."""
1143 POWER_ON = 'power on'
1144 POWER_OFF = 'power off'
1145 REBOOT = 'rebooting'
1146 SUSPEND = 'suspended'
1147
1148
1149class BaremetalProvisionStates(object):
1150 """Possible provision states of an Ironic node."""
1151 NOSTATE = None
1152 INIT = 'initializing'
1153 ACTIVE = 'active'
1154 BUILDING = 'building'
1155 DEPLOYWAIT = 'wait call-back'
1156 DEPLOYING = 'deploying'
1157 DEPLOYFAIL = 'deploy failed'
1158 DEPLOYDONE = 'deploy complete'
1159 DELETING = 'deleting'
1160 DELETED = 'deleted'
1161 ERROR = 'error'
1162
1163
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001164class BaremetalScenarioTest(ScenarioTest):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001165 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001166 def skip_checks(cls):
1167 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001168 if (not CONF.service_available.ironic or
1169 not CONF.baremetal.driver_enabled):
1170 msg = 'Ironic not available or Ironic compute driver not enabled'
1171 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001172
1173 @classmethod
1174 def setup_credentials(cls):
1175 super(BaremetalScenarioTest, cls).setup_credentials()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001176
1177 # use an admin client manager for baremetal client
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001178 manager = clients.Manager(
1179 credentials=cls.admin_credentials()
1180 )
Adam Gandelman4a48a602014-03-20 18:23:18 -07001181 cls.baremetal_client = manager.baremetal_client
1182
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001183 @classmethod
1184 def resource_setup(cls):
1185 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001186 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001187 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001188
1189 def _node_state_timeout(self, node_id, state_attr,
1190 target_states, timeout=10, interval=1):
1191 if not isinstance(target_states, list):
1192 target_states = [target_states]
1193
1194 def check_state():
1195 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001196 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001197 return True
1198 return False
1199
1200 if not tempest.test.call_until_true(
1201 check_state, timeout, interval):
1202 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1203 (node_id, state_attr, target_states))
1204 raise exceptions.TimeoutException(msg)
1205
1206 def wait_provisioning_state(self, node_id, state, timeout):
1207 self._node_state_timeout(
1208 node_id=node_id, state_attr='provision_state',
1209 target_states=state, timeout=timeout)
1210
1211 def wait_power_state(self, node_id, state):
1212 self._node_state_timeout(
1213 node_id=node_id, state_attr='power_state',
1214 target_states=state, timeout=CONF.baremetal.power_timeout)
1215
1216 def wait_node(self, instance_id):
1217 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001218
Adam Gandelman4a48a602014-03-20 18:23:18 -07001219 def _get_node():
1220 node = None
1221 try:
1222 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001223 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001224 pass
1225 return node is not None
1226
1227 if not tempest.test.call_until_true(
1228 _get_node, CONF.baremetal.association_timeout, 1):
1229 msg = ('Timed out waiting to get Ironic node by instance id %s'
1230 % instance_id)
1231 raise exceptions.TimeoutException(msg)
1232
1233 def get_node(self, node_id=None, instance_id=None):
1234 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001235 _, body = self.baremetal_client.show_node(node_id)
1236 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001237 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001238 _, body = self.baremetal_client.show_node_by_instance_uuid(
1239 instance_id)
1240 if body['nodes']:
1241 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001242
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001243 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001244 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001245 _, body = self.baremetal_client.list_node_ports(node_uuid)
1246 for port in body['ports']:
1247 _, p = self.baremetal_client.show_port(port['uuid'])
1248 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001249 return ports
1250
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001251 def add_keypair(self):
1252 self.keypair = self.create_keypair()
1253
1254 def verify_connectivity(self, ip=None):
1255 if ip:
1256 dest = self.get_remote_client(ip)
1257 else:
1258 dest = self.get_remote_client(self.instance)
1259 dest.validate_authentication()
1260
1261 def boot_instance(self):
1262 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001263 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001264 }
1265 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001266 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001267
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001268 self.wait_node(self.instance['id'])
1269 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001270
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001271 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001272
1273 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001274 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001275 [BaremetalProvisionStates.DEPLOYWAIT,
1276 BaremetalProvisionStates.ACTIVE],
1277 timeout=15)
1278
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001279 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001280 BaremetalProvisionStates.ACTIVE,
1281 timeout=CONF.baremetal.active_timeout)
1282
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001283 self.servers_client.wait_for_server_status(self.instance['id'],
1284 'ACTIVE')
1285 self.node = self.get_node(instance_id=self.instance['id'])
David Kranz0fb14292015-02-11 15:55:20 -05001286 self.instance = self.servers_client.get_server(self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001287
1288 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001289 self.servers_client.delete_server(self.instance['id'])
1290 self.wait_power_state(self.node['uuid'],
1291 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001292 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001293 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001294 BaremetalProvisionStates.NOSTATE,
1295 timeout=CONF.baremetal.unprovision_timeout)
1296
Adam Gandelman4a48a602014-03-20 18:23:18 -07001297
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001298class EncryptionScenarioTest(ScenarioTest):
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001299 """
1300 Base class for encryption scenario tests
1301 """
1302
1303 @classmethod
David Kranz4cc852b2015-03-09 14:57:11 -04001304 def skip_checks(cls):
1305 super(EncryptionScenarioTest, cls).skip_checks()
1306 if not credentials.is_admin_available():
1307 msg = ("Missing Identity Admin API credentials in configuration.")
1308 raise cls.skipException(msg)
1309
1310 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001311 def setup_clients(cls):
1312 super(EncryptionScenarioTest, cls).setup_clients()
David Kranz4cc852b2015-03-09 14:57:11 -04001313 admin_manager = clients.Manager(cls.admin_credentials())
1314 cls.admin_volume_types_client = admin_manager.volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001315
1316 def _wait_for_volume_status(self, status):
1317 self.status_timeout(
1318 self.volume_client.volumes, self.volume.id, status)
1319
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001320 def nova_boot(self):
1321 self.keypair = self.create_keypair()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001322 create_kwargs = {'key_name': self.keypair['name']}
1323 self.server = self.create_server(image=self.image,
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001324 create_kwargs=create_kwargs)
1325
1326 def create_volume_type(self, client=None, name=None):
1327 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001328 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001329 if not name:
1330 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001331 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001332 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001333 body = client.create_volume_type(
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001334 randomized_name)
1335 self.assertIn('id', body)
1336 self.addCleanup(client.delete_volume_type, body['id'])
1337 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001338
1339 def create_encryption_type(self, client=None, type_id=None, provider=None,
1340 key_size=None, cipher=None,
1341 control_location=None):
1342 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001343 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001344 if not type_id:
1345 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001346 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001347 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001348 client.create_encryption_type(
1349 type_id, provider=provider, key_size=key_size, cipher=cipher,
1350 control_location=control_location)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001351
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001352
Chris Dent0d494112014-08-26 13:48:30 +01001353class SwiftScenarioTest(ScenarioTest):
1354 """
1355 Provide harness to do Swift scenario tests.
1356
1357 Subclasses implement the tests that use the methods provided by this
1358 class.
1359 """
1360
1361 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001362 def skip_checks(cls):
1363 super(SwiftScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001364 if not CONF.service_available.swift:
1365 skip_msg = ("%s skipped as swift is not available" %
1366 cls.__name__)
1367 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001368
1369 @classmethod
1370 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001371 cls.set_network_resources()
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001372 super(SwiftScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001373 operator_role = CONF.object_storage.operator_role
1374 if not cls.isolated_creds.is_role_available(operator_role):
1375 skip_msg = ("%s skipped because the configured credential provider"
1376 " is not able to provide credentials with the %s role "
1377 "assigned." % (cls.__name__, operator_role))
1378 raise cls.skipException(skip_msg)
1379 else:
1380 cls.os_operator = clients.Manager(
1381 cls.isolated_creds.get_creds_by_roles(
1382 [operator_role]))
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001383
1384 @classmethod
1385 def setup_clients(cls):
1386 super(SwiftScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001387 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001388 cls.account_client = cls.os_operator.account_client
1389 cls.container_client = cls.os_operator.container_client
1390 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001391
Chris Dentde456a12014-09-10 12:41:15 +01001392 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001393 """get swift status for our user account."""
1394 self.account_client.list_account_containers()
1395 LOG.debug('Swift status information obtained successfully')
1396
Chris Dentde456a12014-09-10 12:41:15 +01001397 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001398 name = container_name or data_utils.rand_name(
1399 'swift-scenario-container')
1400 self.container_client.create_container(name)
1401 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001402 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001403 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001404 self.addCleanup(self.delete_wrapper,
1405 self.container_client.delete_container,
1406 name)
Chris Dent0d494112014-08-26 13:48:30 +01001407 return name
1408
Chris Dentde456a12014-09-10 12:41:15 +01001409 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001410 self.container_client.delete_container(container_name)
1411 LOG.debug('Container %s deleted' % (container_name))
1412
Chris Dentde456a12014-09-10 12:41:15 +01001413 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001414 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1415 obj_data = data_utils.arbitrary_string()
1416 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001417 self.addCleanup(self.delete_wrapper,
1418 self.object_client.delete_object,
1419 container_name,
1420 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001421 return obj_name, obj_data
1422
Chris Dentde456a12014-09-10 12:41:15 +01001423 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001424 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001425 self.list_and_check_container_objects(container_name,
1426 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001427
Chris Dentde456a12014-09-10 12:41:15 +01001428 def list_and_check_container_objects(self, container_name,
1429 present_obj=None,
1430 not_present_obj=None):
Chris Dent0d494112014-08-26 13:48:30 +01001431 """
1432 List objects for a given container and assert which are present and
1433 which are not.
1434 """
Ghanshyam2a180b82014-06-16 13:54:22 +09001435 if present_obj is None:
1436 present_obj = []
1437 if not_present_obj is None:
1438 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001439 _, object_list = self.container_client.list_container_contents(
1440 container_name)
1441 if present_obj:
1442 for obj in present_obj:
1443 self.assertIn(obj, object_list)
1444 if not_present_obj:
1445 for obj in not_present_obj:
1446 self.assertNotIn(obj, object_list)
1447
Chris Dentde456a12014-09-10 12:41:15 +01001448 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001449 metadata_param = {'metadata_prefix': 'x-container-',
1450 'metadata': {'read': acl}}
1451 self.container_client.update_container_metadata(container_name,
1452 **metadata_param)
1453 resp, _ = self.container_client.list_container_metadata(container_name)
1454 self.assertEqual(resp['x-container-read'], acl)
1455
Chris Dentde456a12014-09-10 12:41:15 +01001456 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001457 _, obj = self.object_client.get_object(container_name, obj_name)
1458 self.assertEqual(obj, expected_data)