blob: 5f8d605bb25d8e3f5e5d475c381e562b564c9566 [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
Matt Riedemann5f0ac522015-05-21 09:16:24 -070023from tempest_lib.common.utils import misc as misc_utils
Masayuki Igawad9388762015-01-20 14:56:42 +090024from tempest_lib import exceptions as lib_exc
Sean Dague6dbc6da2013-05-08 17:49:46 -040025
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()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700311 except Exception as e:
312 message = ('Initializing SSH connection to %(ip)s failed. '
313 'Error: %(error)s' % {'ip': ip, 'error': e})
314 caller = misc_utils.find_test_caller()
315 if caller:
316 message = '(%s) %s' % (caller, message)
317 LOG.exception(message)
Marc Kodererb06db502015-04-30 09:31:27 +0200318 # If we don't explicitly set for which servers we want to
JordanP3fe2dc32014-11-17 13:06:01 +0100319 # log the console output then all the servers will be logged.
320 # See the definition of _log_console_output()
321 self._log_console_output(log_console_of_servers)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100322 raise
323
324 return linux_client
325
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000326 def _image_create(self, name, fmt, path,
327 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900328 if properties is None:
329 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100330 name = data_utils.rand_name('%s-' % name)
331 image_file = open(path, 'rb')
332 self.addCleanup(image_file.close)
333 params = {
334 'name': name,
335 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000336 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100337 'is_public': 'False',
338 }
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000339 params['properties'] = properties
David Kranz34f18782015-01-06 13:43:55 -0500340 image = self.image_client.create_image(**params)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100341 self.addCleanup(self.image_client.delete_image, image['id'])
342 self.assertEqual("queued", image['status'])
343 self.image_client.update_image(image['id'], data=image_file)
344 return image['id']
345
346 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300347 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100348 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
349 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
350 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300351 img_container_format = CONF.scenario.img_container_format
352 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000353 img_properties = CONF.scenario.img_properties
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300354 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000355 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300356 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000357 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100358 try:
359 self.image = self._image_create('scenario-img',
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300360 img_container_format,
361 img_path,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000362 disk_format=img_disk_format,
363 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100364 except IOError:
365 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
366 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
367 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000368 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100369 self.image = self._image_create('scenario-ami', 'ami',
370 path=ami_img_path,
371 properties=properties)
372 LOG.debug("image:%s" % self.image)
373
374 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400375 if not CONF.compute_feature_enabled.console_output:
376 LOG.debug('Console output not supported, cannot log')
377 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100378 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500379 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100380 servers = servers['servers']
381 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500382 console_output = self.servers_client.get_console_output(
David Kranzae99b9a2015-02-16 13:37:01 -0500383 server['id'], length=None).data
384 LOG.debug('Console output for %s\nbody=\n%s',
385 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100386
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000387 def _log_net_info(self, exc):
388 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300389 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000390 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000391
nithya-ganesan882595e2014-07-29 18:51:07 +0000392 def create_server_snapshot(self, server, name=None):
393 # Glance client
394 _image_client = self.image_client
395 # Compute client
396 _images_client = self.images_client
397 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000398 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000399 LOG.debug("Creating a snapshot image for server: %s", server['name'])
David Kranza5299eb2015-01-15 17:24:05 -0500400 image = _images_client.create_image(server['id'], name)
401 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000402 _image_client.wait_for_image_status(image_id, 'active')
403 self.addCleanup_with_wait(
404 waiter_callable=_image_client.wait_for_resource_deletion,
405 thing_id=image_id, thing_id_param='id',
406 cleanup_callable=self.delete_wrapper,
407 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500408 snapshot_image = _image_client.get_image_meta(image_id)
nithya-ganesan882595e2014-07-29 18:51:07 +0000409 image_name = snapshot_image['name']
410 self.assertEqual(name, image_name)
411 LOG.debug("Created snapshot image %s for server %s",
412 image_name, server['name'])
413 return snapshot_image
414
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900415 def nova_volume_attach(self):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000416 volume = self.servers_client.attach_volume(
Alexander Gubanove0634ab2015-05-25 10:28:25 +0300417 self.server['id'], self.volume['id'], '/dev/%s'
418 % CONF.compute.volume_device_name)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900419 self.assertEqual(self.volume['id'], volume['id'])
420 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
421 # Refresh the volume after the attachment
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000422 self.volume = self.volumes_client.show_volume(volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900423
424 def nova_volume_detach(self):
425 self.servers_client.detach_volume(self.server['id'], self.volume['id'])
426 self.volumes_client.wait_for_volume_status(self.volume['id'],
427 'available')
428
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000429 volume = self.volumes_client.show_volume(self.volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900430 self.assertEqual('available', volume['status'])
431
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700432 def rebuild_server(self, server_id, image=None,
433 preserve_ephemeral=False, wait=True,
434 rebuild_kwargs=None):
435 if image is None:
436 image = CONF.compute.image_ref
437
438 rebuild_kwargs = rebuild_kwargs or {}
439
440 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
441 server_id, image, preserve_ephemeral)
442 self.servers_client.rebuild(server_id=server_id, image_ref=image,
443 preserve_ephemeral=preserve_ephemeral,
444 **rebuild_kwargs)
445 if wait:
446 self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
447
Steven Hardyda2a8352014-10-02 12:52:20 +0100448 def ping_ip_address(self, ip_address, should_succeed=True,
449 ping_timeout=None):
450 timeout = ping_timeout or CONF.compute.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700451 cmd = ['ping', '-c1', '-w1', ip_address]
452
453 def ping():
454 proc = subprocess.Popen(cmd,
455 stdout=subprocess.PIPE,
456 stderr=subprocess.PIPE)
457 proc.communicate()
458 return (proc.returncode == 0) == should_succeed
459
Steven Hardyda2a8352014-10-02 12:52:20 +0100460 return tempest.test.call_until_true(ping, timeout, 1)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700461
Yair Friedae0e73d2014-11-24 11:56:26 +0200462 def check_vm_connectivity(self, ip_address,
463 username=None,
464 private_key=None,
465 should_connect=True):
466 """
467 :param ip_address: server to test against
468 :param username: server's ssh username
469 :param private_key: server's ssh private key to be used
470 :param should_connect: True/False indicates positive/negative test
471 positive - attempt ping and ssh
472 negative - attempt ping and fail if succeed
473
474 :raises: AssertError if the result of the connectivity check does
475 not match the value of the should_connect param
476 """
477 if should_connect:
478 msg = "Timed out waiting for %s to become reachable" % ip_address
479 else:
480 msg = "ip address %s is reachable" % ip_address
481 self.assertTrue(self.ping_ip_address(ip_address,
482 should_succeed=should_connect),
483 msg=msg)
484 if should_connect:
485 # no need to check ssh for negative connectivity
486 self.get_remote_client(ip_address, username, private_key)
487
488 def check_public_network_connectivity(self, ip_address, username,
489 private_key, should_connect=True,
490 msg=None, servers=None):
491 # The target login is assumed to have been configured for
492 # key-based authentication by cloud-init.
493 LOG.debug('checking network connections to IP %s with user: %s' %
494 (ip_address, username))
495 try:
496 self.check_vm_connectivity(ip_address,
497 username,
498 private_key,
499 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500500 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200501 ex_msg = 'Public network connectivity check failed'
502 if msg:
503 ex_msg += ": " + msg
504 LOG.exception(ex_msg)
505 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200506 raise
507
508 def create_floating_ip(self, thing, pool_name=None):
509 """Creates a floating IP and associates to a server using
510 Nova clients
511 """
512
David Kranze4e3b412015-02-10 10:50:42 -0500513 floating_ip = self.floating_ips_client.create_floating_ip(pool_name)
Yair Friedae0e73d2014-11-24 11:56:26 +0200514 self.addCleanup(self.delete_wrapper,
515 self.floating_ips_client.delete_floating_ip,
516 floating_ip['id'])
517 self.floating_ips_client.associate_floating_ip_to_server(
518 floating_ip['ip'], thing['id'])
519 return floating_ip
520
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100521
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100522class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300523 """Base class for network scenario tests.
524 This class provide helpers for network scenario tests, using the neutron
525 API. Helpers from ancestor which use the nova network API are overridden
526 with the neutron API.
527
528 This Class also enforces using Neutron instead of novanetwork.
529 Subclassed tests will be skipped if Neutron is not enabled
530
531 """
532
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000533 credentials = ['primary', 'admin']
534
Yair Fried1fc32a12014-08-04 09:11:30 +0300535 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000536 def skip_checks(cls):
537 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100538 if not CONF.service_available.neutron:
539 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300540
541 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100542 def resource_setup(cls):
543 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300544 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300545
Yair Frieddb6c9e92014-08-06 08:53:13 +0300546 def _create_network(self, client=None, tenant_id=None,
547 namestart='network-smoke-'):
548 if not client:
549 client = self.network_client
550 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000551 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300552 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500553 result = client.create_network(name=name, tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300554 network = net_resources.DeletableNetwork(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300555 **result['network'])
556 self.assertEqual(network.name, name)
557 self.addCleanup(self.delete_wrapper, network.delete)
558 return network
559
560 def _list_networks(self, *args, **kwargs):
561 """List networks using admin creds """
562 return self._admin_lister('networks')(*args, **kwargs)
563
564 def _list_subnets(self, *args, **kwargs):
565 """List subnets using admin creds """
566 return self._admin_lister('subnets')(*args, **kwargs)
567
568 def _list_routers(self, *args, **kwargs):
569 """List routers using admin creds """
570 return self._admin_lister('routers')(*args, **kwargs)
571
572 def _list_ports(self, *args, **kwargs):
573 """List ports using admin creds """
574 return self._admin_lister('ports')(*args, **kwargs)
575
576 def _admin_lister(self, resource_type):
577 def temp(*args, **kwargs):
578 temp_method = self.admin_manager.network_client.__getattr__(
579 'list_%s' % resource_type)
David Kranz34e88122014-12-11 15:24:05 -0500580 resource_list = temp_method(*args, **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300581 return resource_list[resource_type]
582 return temp
583
Yair Frieddb6c9e92014-08-06 08:53:13 +0300584 def _create_subnet(self, network, client=None, namestart='subnet-smoke',
585 **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300586 """
587 Create a subnet for the given network within the cidr block
588 configured for tenant networks.
589 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300590 if not client:
591 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300592
593 def cidr_in_use(cidr, tenant_id):
594 """
595 :return True if subnet with cidr already exist in tenant
596 False else
597 """
598 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
599 return len(cidr_in_use) != 0
600
Kirill Shileev14113572014-11-21 16:58:02 +0300601 ip_version = kwargs.pop('ip_version', 4)
602
603 if ip_version == 6:
604 tenant_cidr = netaddr.IPNetwork(
605 CONF.network.tenant_network_v6_cidr)
606 num_bits = CONF.network.tenant_network_v6_mask_bits
607 else:
608 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
609 num_bits = CONF.network.tenant_network_mask_bits
610
Yair Fried1fc32a12014-08-04 09:11:30 +0300611 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300612 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300613 # Repeatedly attempt subnet creation with sequential cidr
614 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300615 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300616 str_cidr = str(subnet_cidr)
617 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
618 continue
619
620 subnet = dict(
621 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300622 network_id=network.id,
623 tenant_id=network.tenant_id,
624 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300625 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300626 **kwargs
627 )
628 try:
David Kranz34e88122014-12-11 15:24:05 -0500629 result = client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300630 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900631 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300632 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
633 if not is_overlapping_cidr:
634 raise
635 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300636 subnet = net_resources.DeletableSubnet(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300637 **result['subnet'])
638 self.assertEqual(subnet.cidr, str_cidr)
639 self.addCleanup(self.delete_wrapper, subnet.delete)
640 return subnet
641
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200642 def _create_port(self, network_id, client=None, namestart='port-quotatest',
643 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300644 if not client:
645 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300646 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500647 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300648 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200649 network_id=network_id,
650 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300651 self.assertIsNotNone(result, 'Unable to allocate port')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300652 port = net_resources.DeletablePort(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300653 **result['port'])
654 self.addCleanup(self.delete_wrapper, port.delete)
655 return port
656
Kirill Shileev14113572014-11-21 16:58:02 +0300657 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300658 ports = self._list_ports(device_id=server['id'],
659 fixed_ip=ip_addr)
660 self.assertEqual(len(ports), 1,
661 "Unable to determine which port to target.")
Kirill Shileev14113572014-11-21 16:58:02 +0300662 # it might happen here that this port has more then one ip address
663 # as in case of dual stack- when this port is created on 2 subnets
664 for ip46 in ports[0]['fixed_ips']:
665 ip = ip46['ip_address']
666 if netaddr.valid_ipv4(ip):
667 return ports[0]['id'], ip
Yair Fried1fc32a12014-08-04 09:11:30 +0300668
David Shrewsbury9bac3662014-08-07 15:07:01 -0400669 def _get_network_by_name(self, network_name):
670 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700671 self.assertNotEqual(len(net), 0,
672 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300673 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400674
Yair Friedae0e73d2014-11-24 11:56:26 +0200675 def create_floating_ip(self, thing, external_network_id=None,
676 port_id=None, client=None):
677 """Creates a floating IP and associates to a resource/port using
678 Neutron client
679 """
680 if not external_network_id:
681 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300682 if not client:
683 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300684 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300685 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
686 else:
687 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500688 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300689 floating_network_id=external_network_id,
690 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300691 tenant_id=thing['tenant_id'],
692 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300693 )
694 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300695 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300696 **result['floatingip'])
697 self.addCleanup(self.delete_wrapper, floating_ip.delete)
698 return floating_ip
699
700 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300701 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300702 floating_ip.update(port_id=port_id)
703 self.assertEqual(port_id, floating_ip.port_id)
704 return floating_ip
705
706 def _disassociate_floating_ip(self, floating_ip):
707 """
708 :param floating_ip: type DeletableFloatingIp
709 """
710 floating_ip.update(port_id=None)
711 self.assertIsNone(floating_ip.port_id)
712 return floating_ip
713
Yair Fried45f92952014-06-26 05:19:19 +0300714 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000715 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300716
717 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
718 to check status
719 :param status: target status
720 :raises: AssertionError if status doesn't match
721 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000722 def refresh():
723 floating_ip.refresh()
724 return status == floating_ip.status
725
726 tempest.test.call_until_true(refresh,
727 CONF.network.build_timeout,
728 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300729 self.assertEqual(status, floating_ip.status,
730 message="FloatingIP: {fp} is at status: {cst}. "
731 "failed to reach status: {st}"
732 .format(fp=floating_ip, cst=floating_ip.status,
733 st=status))
734 LOG.info("FloatingIP: {fp} is at status: {st}"
735 .format(fp=floating_ip, st=status))
736
Yair Fried1fc32a12014-08-04 09:11:30 +0300737 def _check_tenant_network_connectivity(self, server,
738 username,
739 private_key,
740 should_connect=True,
741 servers_for_debug=None):
742 if not CONF.network.tenant_networks_reachable:
743 msg = 'Tenant networks not configured to be reachable.'
744 LOG.info(msg)
745 return
746 # The target login is assumed to have been configured for
747 # key-based authentication by cloud-init.
748 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400749 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300750 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900751 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200752 username,
753 private_key,
754 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300755 except Exception as e:
756 LOG.exception('Tenant network connectivity check failed')
757 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000758 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300759 raise
760
761 def _check_remote_connectivity(self, source, dest, should_succeed=True):
762 """
763 check ping server via source ssh connection
764
765 :param source: RemoteClient: an ssh connection from which to ping
766 :param dest: and IP to ping against
767 :param should_succeed: boolean should ping succeed or not
768 :returns: boolean -- should_succeed == ping
769 :returns: ping is false if ping failed
770 """
771 def ping_remote():
772 try:
773 source.ping_host(dest)
Andrey Pavlov64723762015-04-29 06:24:58 +0300774 except lib_exc.SSHExecCommandFailed:
Yair Fried1fc32a12014-08-04 09:11:30 +0300775 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
776 % (dest, source.ssh_client.host))
777 return not should_succeed
778 return should_succeed
779
780 return tempest.test.call_until_true(ping_remote,
781 CONF.compute.ping_timeout,
782 1)
783
Yair Frieddb6c9e92014-08-06 08:53:13 +0300784 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300785 namestart='secgroup-smoke'):
786 if client is None:
787 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300788 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000789 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300790 secgroup = self._create_empty_security_group(namestart=namestart,
791 client=client,
792 tenant_id=tenant_id)
793
794 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900795 rules = self._create_loginable_secgroup_rule(client=client,
796 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300797 for rule in rules:
798 self.assertEqual(tenant_id, rule.tenant_id)
799 self.assertEqual(secgroup.id, rule.security_group_id)
800 return secgroup
801
Yair Frieddb6c9e92014-08-06 08:53:13 +0300802 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300803 namestart='secgroup-smoke'):
804 """Create a security group without rules.
805
806 Default rules will be created:
807 - IPv4 egress to any
808 - IPv6 egress to any
809
810 :param tenant_id: secgroup will be created in this tenant
811 :returns: DeletableSecurityGroup -- containing the secgroup created
812 """
813 if client is None:
814 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300815 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000816 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300817 sg_name = data_utils.rand_name(namestart)
818 sg_desc = sg_name + " description"
819 sg_dict = dict(name=sg_name,
820 description=sg_desc)
821 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500822 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300823 secgroup = net_resources.DeletableSecurityGroup(
824 client=client,
825 **result['security_group']
826 )
827 self.assertEqual(secgroup.name, sg_name)
828 self.assertEqual(tenant_id, secgroup.tenant_id)
829 self.assertEqual(secgroup.description, sg_desc)
830 self.addCleanup(self.delete_wrapper, secgroup.delete)
831 return secgroup
832
Yair Frieddb6c9e92014-08-06 08:53:13 +0300833 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300834 """Get default secgroup for given tenant_id.
835
836 :returns: DeletableSecurityGroup -- default secgroup for given tenant
837 """
838 if client is None:
839 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300840 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000841 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300842 sgs = [
843 sg for sg in client.list_security_groups().values()[0]
844 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
845 ]
846 msg = "No default security group for tenant %s." % (tenant_id)
847 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300848 return net_resources.DeletableSecurityGroup(client=client,
849 **sgs[0])
850
Yair Frieddb6c9e92014-08-06 08:53:13 +0300851 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300852 tenant_id=None, **kwargs):
853 """Create a rule from a dictionary of rule parameters.
854
855 Create a rule in a secgroup. if secgroup not defined will search for
856 default secgroup in tenant_id.
857
858 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300859 :param tenant_id: if secgroup not passed -- the tenant in which to
860 search for default secgroup
861 :param kwargs: a dictionary containing rule parameters:
862 for example, to allow incoming ssh:
863 rule = {
864 direction: 'ingress'
865 protocol:'tcp',
866 port_range_min: 22,
867 port_range_max: 22
868 }
869 """
870 if client is None:
871 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300872 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000873 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300874 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300875 secgroup = self._default_security_group(client=client,
876 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300877
878 ruleset = dict(security_group_id=secgroup.id,
879 tenant_id=secgroup.tenant_id)
880 ruleset.update(kwargs)
881
David Kranz34e88122014-12-11 15:24:05 -0500882 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300883 sg_rule = net_resources.DeletableSecurityGroupRule(
884 client=client,
885 **sg_rule['security_group_rule']
886 )
887 self.addCleanup(self.delete_wrapper, sg_rule.delete)
888 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
889 self.assertEqual(secgroup.id, sg_rule.security_group_id)
890
891 return sg_rule
892
893 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
894 """These rules are intended to permit inbound ssh and icmp
895 traffic from all sources, so no group_id is provided.
896 Setting a group_id would only permit traffic from ports
897 belonging to the same security group.
898 """
899
900 if client is None:
901 client = self.network_client
902 rules = []
903 rulesets = [
904 dict(
905 # ssh
906 protocol='tcp',
907 port_range_min=22,
908 port_range_max=22,
909 ),
910 dict(
911 # ping
912 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +0100913 ),
914 dict(
915 # ipv6-icmp for ping6
916 protocol='icmp',
917 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +0300918 )
919 ]
920 for ruleset in rulesets:
921 for r_direction in ['ingress', 'egress']:
922 ruleset['direction'] = r_direction
923 try:
924 sg_rule = self._create_security_group_rule(
925 client=client, secgroup=secgroup, **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +0900926 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +0300927 # if rule already exist - skip rule and continue
928 msg = 'Security group rule already exists'
929 if msg not in ex._error_string:
930 raise ex
931 else:
932 self.assertEqual(r_direction, sg_rule.direction)
933 rules.append(sg_rule)
934
935 return rules
936
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500937 def _create_pool(self, lb_method, protocol, subnet_id):
938 """Wrapper utility that returns a test pool."""
939 client = self.network_client
940 name = data_utils.rand_name('pool')
David Kranz34e88122014-12-11 15:24:05 -0500941 resp_pool = client.create_pool(protocol=protocol, name=name,
942 subnet_id=subnet_id,
943 lb_method=lb_method)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500944 pool = net_resources.DeletablePool(client=client, **resp_pool['pool'])
945 self.assertEqual(pool['name'], name)
946 self.addCleanup(self.delete_wrapper, pool.delete)
947 return pool
948
949 def _create_member(self, address, protocol_port, pool_id):
950 """Wrapper utility that returns a test member."""
951 client = self.network_client
David Kranz34e88122014-12-11 15:24:05 -0500952 resp_member = client.create_member(protocol_port=protocol_port,
953 pool_id=pool_id,
954 address=address)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500955 member = net_resources.DeletableMember(client=client,
956 **resp_member['member'])
957 self.addCleanup(self.delete_wrapper, member.delete)
958 return member
959
960 def _create_vip(self, protocol, protocol_port, subnet_id, pool_id):
961 """Wrapper utility that returns a test vip."""
962 client = self.network_client
963 name = data_utils.rand_name('vip')
David Kranz34e88122014-12-11 15:24:05 -0500964 resp_vip = client.create_vip(protocol=protocol, name=name,
965 subnet_id=subnet_id, pool_id=pool_id,
966 protocol_port=protocol_port)
Miguel Lavalle02ba8cd2014-09-01 19:23:22 -0500967 vip = net_resources.DeletableVip(client=client, **resp_vip['vip'])
968 self.assertEqual(vip['name'], name)
969 self.addCleanup(self.delete_wrapper, vip.delete)
970 return vip
971
Yair Fried1fc32a12014-08-04 09:11:30 +0300972 def _ssh_to_server(self, server, private_key):
973 ssh_login = CONF.compute.image_ssh_user
974 return self.get_remote_client(server,
975 username=ssh_login,
976 private_key=private_key)
977
Yair Frieddb6c9e92014-08-06 08:53:13 +0300978 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300979 """Retrieve a router for the given tenant id.
980
981 If a public router has been configured, it will be returned.
982
983 If a public router has not been configured, but a public
984 network has, a tenant router will be created and returned that
985 routes traffic to the public network.
986 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300987 if not client:
988 client = self.network_client
989 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000990 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300991 router_id = CONF.network.public_router_id
992 network_id = CONF.network.public_network_id
993 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -0400994 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +0400995 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300996 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300997 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300998 router.set_gateway(network_id)
999 return router
1000 else:
1001 raise Exception("Neither of 'public_router_id' or "
1002 "'public_network_id' has been defined.")
1003
Yair Frieddb6c9e92014-08-06 08:53:13 +03001004 def _create_router(self, client=None, tenant_id=None,
1005 namestart='router-smoke'):
1006 if not client:
1007 client = self.network_client
1008 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001009 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001010 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001011 result = client.create_router(name=name,
1012 admin_state_up=True,
1013 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001014 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001015 **result['router'])
1016 self.assertEqual(router.name, name)
1017 self.addCleanup(self.delete_wrapper, router.delete)
1018 return router
1019
Alok Maurya6384bbb2014-07-13 06:44:29 -07001020 def _update_router_admin_state(self, router, admin_state_up):
1021 router.update(admin_state_up=admin_state_up)
1022 self.assertEqual(admin_state_up, router.admin_state_up)
1023
Yair Fried413bf2d2014-11-19 17:07:11 +02001024 def create_networks(self, client=None, tenant_id=None,
1025 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001026 """Create a network with a subnet connected to a router.
1027
David Shrewsbury9bac3662014-08-07 15:07:01 -04001028 The baremetal driver is a special case since all nodes are
1029 on the same shared network.
1030
Yair Fried413bf2d2014-11-19 17:07:11 +02001031 :param client: network client to create resources with.
1032 :param tenant_id: id of tenant to create resources in.
1033 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001034 :returns: network, subnet, router
1035 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001036 if CONF.baremetal.driver_enabled:
1037 # NOTE(Shrews): This exception is for environments where tenant
1038 # credential isolation is available, but network separation is
1039 # not (the current baremetal case). Likely can be removed when
1040 # test account mgmt is reworked:
1041 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001042 if not CONF.compute.fixed_network_name:
1043 m = 'fixed_network_name must be specified in config'
1044 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001045 network = self._get_network_by_name(
1046 CONF.compute.fixed_network_name)
1047 router = None
1048 subnet = None
1049 else:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001050 network = self._create_network(client=client, tenant_id=tenant_id)
1051 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001052
1053 subnet_kwargs = dict(network=network, client=client)
1054 # use explicit check because empty list is a valid option
1055 if dns_nameservers is not None:
1056 subnet_kwargs['dns_nameservers'] = dns_nameservers
1057 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001058 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001059 return network, subnet, router
1060
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001061 def create_server(self, name=None, image=None, flavor=None,
1062 wait_on_boot=True, wait_on_delete=True,
1063 create_kwargs=None):
1064 vnic_type = CONF.network.port_vnic_type
1065
1066 # If vnic_type is configured create port for
1067 # every network
1068 if vnic_type:
1069 ports = []
1070 networks = []
1071 create_port_body = {'binding:vnic_type': vnic_type,
1072 'namestart': 'port-smoke'}
1073 if create_kwargs:
1074 net_client = create_kwargs.get("network_client",
1075 self.network_client)
1076
1077 # Convert security group names to security group ids
1078 # to pass to create_port
1079 if create_kwargs.get('security_groups'):
1080 security_groups = net_client.list_security_groups().get(
1081 'security_groups')
1082 sec_dict = dict([(s['name'], s['id'])
1083 for s in security_groups])
1084
1085 sec_groups_names = [s['name'] for s in create_kwargs[
1086 'security_groups']]
1087 security_groups_ids = [sec_dict[s]
1088 for s in sec_groups_names]
1089
1090 if security_groups_ids:
1091 create_port_body[
1092 'security_groups'] = security_groups_ids
1093 networks = create_kwargs.get('networks')
1094 else:
1095 net_client = self.network_client
1096 # If there are no networks passed to us we look up
1097 # for the tenant's private networks and create a port
1098 # if there is only one private network. The same behaviour
1099 # as we would expect when passing the call to the clients
1100 # with no networks
1101 if not networks:
1102 networks = net_client.list_networks(filters={
1103 'router:external': False})
1104 self.assertEqual(1, len(networks),
1105 "There is more than one"
1106 " network for the tenant")
1107 for net in networks:
1108 net_id = net['uuid']
1109 port = self._create_port(network_id=net_id,
1110 client=net_client,
1111 **create_port_body)
1112 ports.append({'port': port.id})
1113 if ports:
1114 create_kwargs['networks'] = ports
1115
1116 return super(NetworkScenarioTest, self).create_server(
1117 name=name, image=image, flavor=flavor,
1118 wait_on_boot=wait_on_boot, wait_on_delete=wait_on_delete,
1119 create_kwargs=create_kwargs)
1120
Yair Fried1fc32a12014-08-04 09:11:30 +03001121
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001122# power/provision states as of icehouse
1123class BaremetalPowerStates(object):
1124 """Possible power states of an Ironic node."""
1125 POWER_ON = 'power on'
1126 POWER_OFF = 'power off'
1127 REBOOT = 'rebooting'
1128 SUSPEND = 'suspended'
1129
1130
1131class BaremetalProvisionStates(object):
1132 """Possible provision states of an Ironic node."""
1133 NOSTATE = None
1134 INIT = 'initializing'
1135 ACTIVE = 'active'
1136 BUILDING = 'building'
1137 DEPLOYWAIT = 'wait call-back'
1138 DEPLOYING = 'deploying'
1139 DEPLOYFAIL = 'deploy failed'
1140 DEPLOYDONE = 'deploy complete'
1141 DELETING = 'deleting'
1142 DELETED = 'deleted'
1143 ERROR = 'error'
1144
1145
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001146class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001147
1148 credentials = ['primary', 'admin']
1149
Adam Gandelman4a48a602014-03-20 18:23:18 -07001150 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001151 def skip_checks(cls):
1152 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001153 if (not CONF.service_available.ironic or
1154 not CONF.baremetal.driver_enabled):
1155 msg = 'Ironic not available or Ironic compute driver not enabled'
1156 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001157
1158 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001159 def setup_clients(cls):
1160 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001161
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001162 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001163
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001164 @classmethod
1165 def resource_setup(cls):
1166 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001167 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001168 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001169
1170 def _node_state_timeout(self, node_id, state_attr,
1171 target_states, timeout=10, interval=1):
1172 if not isinstance(target_states, list):
1173 target_states = [target_states]
1174
1175 def check_state():
1176 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001177 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001178 return True
1179 return False
1180
1181 if not tempest.test.call_until_true(
1182 check_state, timeout, interval):
1183 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1184 (node_id, state_attr, target_states))
1185 raise exceptions.TimeoutException(msg)
1186
1187 def wait_provisioning_state(self, node_id, state, timeout):
1188 self._node_state_timeout(
1189 node_id=node_id, state_attr='provision_state',
1190 target_states=state, timeout=timeout)
1191
1192 def wait_power_state(self, node_id, state):
1193 self._node_state_timeout(
1194 node_id=node_id, state_attr='power_state',
1195 target_states=state, timeout=CONF.baremetal.power_timeout)
1196
1197 def wait_node(self, instance_id):
1198 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001199
Adam Gandelman4a48a602014-03-20 18:23:18 -07001200 def _get_node():
1201 node = None
1202 try:
1203 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001204 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001205 pass
1206 return node is not None
1207
1208 if not tempest.test.call_until_true(
1209 _get_node, CONF.baremetal.association_timeout, 1):
1210 msg = ('Timed out waiting to get Ironic node by instance id %s'
1211 % instance_id)
1212 raise exceptions.TimeoutException(msg)
1213
1214 def get_node(self, node_id=None, instance_id=None):
1215 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001216 _, body = self.baremetal_client.show_node(node_id)
1217 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001218 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001219 _, body = self.baremetal_client.show_node_by_instance_uuid(
1220 instance_id)
1221 if body['nodes']:
1222 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001223
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001224 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001225 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001226 _, body = self.baremetal_client.list_node_ports(node_uuid)
1227 for port in body['ports']:
1228 _, p = self.baremetal_client.show_port(port['uuid'])
1229 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001230 return ports
1231
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001232 def add_keypair(self):
1233 self.keypair = self.create_keypair()
1234
1235 def verify_connectivity(self, ip=None):
1236 if ip:
1237 dest = self.get_remote_client(ip)
1238 else:
1239 dest = self.get_remote_client(self.instance)
1240 dest.validate_authentication()
1241
1242 def boot_instance(self):
1243 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001244 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001245 }
1246 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001247 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001248
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001249 self.wait_node(self.instance['id'])
1250 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001251
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001252 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001253
1254 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001255 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001256 [BaremetalProvisionStates.DEPLOYWAIT,
1257 BaremetalProvisionStates.ACTIVE],
1258 timeout=15)
1259
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001260 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001261 BaremetalProvisionStates.ACTIVE,
1262 timeout=CONF.baremetal.active_timeout)
1263
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001264 self.servers_client.wait_for_server_status(self.instance['id'],
1265 'ACTIVE')
1266 self.node = self.get_node(instance_id=self.instance['id'])
David Kranz0fb14292015-02-11 15:55:20 -05001267 self.instance = self.servers_client.get_server(self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001268
1269 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001270 self.servers_client.delete_server(self.instance['id'])
1271 self.wait_power_state(self.node['uuid'],
1272 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001273 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001274 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001275 BaremetalProvisionStates.NOSTATE,
1276 timeout=CONF.baremetal.unprovision_timeout)
1277
Adam Gandelman4a48a602014-03-20 18:23:18 -07001278
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001279class EncryptionScenarioTest(ScenarioTest):
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001280 """
1281 Base class for encryption scenario tests
1282 """
1283
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001284 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001285
1286 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001287 def setup_clients(cls):
1288 super(EncryptionScenarioTest, cls).setup_clients()
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001289 cls.admin_volume_types_client = cls.os_adm.volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001290
1291 def _wait_for_volume_status(self, status):
1292 self.status_timeout(
1293 self.volume_client.volumes, self.volume.id, status)
1294
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001295 def nova_boot(self):
1296 self.keypair = self.create_keypair()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001297 create_kwargs = {'key_name': self.keypair['name']}
1298 self.server = self.create_server(image=self.image,
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001299 create_kwargs=create_kwargs)
1300
1301 def create_volume_type(self, client=None, name=None):
1302 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001303 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001304 if not name:
1305 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001306 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001307 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001308 body = client.create_volume_type(
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001309 randomized_name)
1310 self.assertIn('id', body)
1311 self.addCleanup(client.delete_volume_type, body['id'])
1312 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001313
1314 def create_encryption_type(self, client=None, type_id=None, provider=None,
1315 key_size=None, cipher=None,
1316 control_location=None):
1317 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001318 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001319 if not type_id:
1320 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001321 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001322 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001323 client.create_encryption_type(
1324 type_id, provider=provider, key_size=key_size, cipher=cipher,
1325 control_location=control_location)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001326
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001327
Chris Dent0d494112014-08-26 13:48:30 +01001328class SwiftScenarioTest(ScenarioTest):
1329 """
1330 Provide harness to do Swift scenario tests.
1331
1332 Subclasses implement the tests that use the methods provided by this
1333 class.
1334 """
1335
1336 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001337 def skip_checks(cls):
1338 super(SwiftScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001339 if not CONF.service_available.swift:
1340 skip_msg = ("%s skipped as swift is not available" %
1341 cls.__name__)
1342 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001343
1344 @classmethod
1345 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001346 cls.set_network_resources()
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001347 super(SwiftScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001348 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001349 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001350
1351 @classmethod
1352 def setup_clients(cls):
1353 super(SwiftScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001354 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001355 cls.account_client = cls.os_operator.account_client
1356 cls.container_client = cls.os_operator.container_client
1357 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001358
Chris Dentde456a12014-09-10 12:41:15 +01001359 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001360 """get swift status for our user account."""
1361 self.account_client.list_account_containers()
1362 LOG.debug('Swift status information obtained successfully')
1363
Chris Dentde456a12014-09-10 12:41:15 +01001364 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001365 name = container_name or data_utils.rand_name(
1366 'swift-scenario-container')
1367 self.container_client.create_container(name)
1368 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001369 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001370 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001371 self.addCleanup(self.delete_wrapper,
1372 self.container_client.delete_container,
1373 name)
Chris Dent0d494112014-08-26 13:48:30 +01001374 return name
1375
Chris Dentde456a12014-09-10 12:41:15 +01001376 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001377 self.container_client.delete_container(container_name)
1378 LOG.debug('Container %s deleted' % (container_name))
1379
Chris Dentde456a12014-09-10 12:41:15 +01001380 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001381 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1382 obj_data = data_utils.arbitrary_string()
1383 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001384 self.addCleanup(self.delete_wrapper,
1385 self.object_client.delete_object,
1386 container_name,
1387 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001388 return obj_name, obj_data
1389
Chris Dentde456a12014-09-10 12:41:15 +01001390 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001391 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001392 self.list_and_check_container_objects(container_name,
1393 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001394
Chris Dentde456a12014-09-10 12:41:15 +01001395 def list_and_check_container_objects(self, container_name,
1396 present_obj=None,
1397 not_present_obj=None):
Chris Dent0d494112014-08-26 13:48:30 +01001398 """
1399 List objects for a given container and assert which are present and
1400 which are not.
1401 """
Ghanshyam2a180b82014-06-16 13:54:22 +09001402 if present_obj is None:
1403 present_obj = []
1404 if not_present_obj is None:
1405 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001406 _, object_list = self.container_client.list_container_contents(
1407 container_name)
1408 if present_obj:
1409 for obj in present_obj:
1410 self.assertIn(obj, object_list)
1411 if not_present_obj:
1412 for obj in not_present_obj:
1413 self.assertNotIn(obj, object_list)
1414
Chris Dentde456a12014-09-10 12:41:15 +01001415 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001416 metadata_param = {'metadata_prefix': 'x-container-',
1417 'metadata': {'read': acl}}
1418 self.container_client.update_container_metadata(container_name,
1419 **metadata_param)
1420 resp, _ = self.container_client.list_container_metadata(container_name)
1421 self.assertEqual(resp['x-container-read'], acl)
1422
Chris Dentde456a12014-09-10 12:41:15 +01001423 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001424 _, obj = self.object_client.get_object(container_name, obj_name)
1425 self.assertEqual(obj, expected_data)