blob: 4b84da1db2cb5567bc920d2e0d1b61b91e40c6cb [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
Matt Riedemann5f0ac522015-05-21 09:16:24 -070022from tempest_lib.common.utils import misc as misc_utils
Masayuki Igawad9388762015-01-20 14:56:42 +090023from tempest_lib import exceptions as lib_exc
Sean Dague6dbc6da2013-05-08 17:49:46 -040024
Rohan Kanade9ce97df2013-12-10 18:59:35 +053025from tempest.common import fixed_network
Fei Long Wangd39431f2015-05-14 11:30:48 +120026from tempest.common.utils import data_utils
Masayuki Igawa4ded9f02014-02-17 15:05:59 +090027from tempest.common.utils.linux import remote_client
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +000028from tempest.common import waiters
Matthew Treinish6c072292014-01-29 19:15:52 +000029from tempest import config
Giulio Fidente92f77192013-08-26 17:13:28 +020030from tempest import exceptions
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
Andrea Frittolib21de6c2015-02-06 20:12:38 +000042 credentials = ['primary']
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000043
44 @classmethod
45 def setup_clients(cls):
46 super(ScenarioTest, cls).setup_clients()
Andrea Frittoli247058f2014-07-16 16:09:22 +010047 # Clients (in alphabetical order)
Adam Gandelmanc78c7572014-08-28 18:38:55 -070048 cls.flavors_client = cls.manager.flavors_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010049 cls.floating_ips_client = cls.manager.floating_ips_client
50 # Glance image client v1
51 cls.image_client = cls.manager.image_client
nithya-ganesan882595e2014-07-29 18:51:07 +000052 # Compute image client
53 cls.images_client = cls.manager.images_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010054 cls.keypairs_client = cls.manager.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010055 # Nova security groups client
56 cls.security_groups_client = cls.manager.security_groups_client
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +000057 cls.security_group_rules_client = (
58 cls.manager.security_group_rules_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +010059 cls.servers_client = cls.manager.servers_client
60 cls.volumes_client = cls.manager.volumes_client
Joseph Lanouxeef192f2014-08-01 14:32:53 +000061 cls.snapshots_client = cls.manager.snapshots_client
Yair Fried1fc32a12014-08-04 09:11:30 +030062 cls.interface_client = cls.manager.interfaces_client
63 # Neutron network client
64 cls.network_client = cls.manager.network_client
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090065 # Heat client
66 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010067
Andrea Frittoli247058f2014-07-16 16:09:22 +010068 # ## Methods to handle sync and async deletes
69
70 def setUp(self):
71 super(ScenarioTest, self).setUp()
72 self.cleanup_waits = []
73 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
74 # because scenario tests in the same test class should not share
75 # resources. If resources were shared between test cases then it
76 # should be a single scenario test instead of multiples.
77
78 # NOTE(yfried): this list is cleaned at the end of test_methods and
79 # not at the end of the class
80 self.addCleanup(self._wait_for_cleanups)
81
Yair Fried1fc32a12014-08-04 09:11:30 +030082 def delete_wrapper(self, delete_thing, *args, **kwargs):
Andrea Frittoli247058f2014-07-16 16:09:22 +010083 """Ignores NotFound exceptions for delete operations.
84
Yair Fried1fc32a12014-08-04 09:11:30 +030085 @param delete_thing: delete method of a resource. method will be
86 executed as delete_thing(*args, **kwargs)
87
Andrea Frittoli247058f2014-07-16 16:09:22 +010088 """
89 try:
90 # Tempest clients return dicts, so there is no common delete
91 # method available. Using a callable instead
Yair Fried1fc32a12014-08-04 09:11:30 +030092 delete_thing(*args, **kwargs)
Masayuki Igawabfa07602015-01-20 18:47:17 +090093 except lib_exc.NotFound:
Andrea Frittoli247058f2014-07-16 16:09:22 +010094 # If the resource is already missing, mission accomplished.
95 pass
96
97 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +090098 cleanup_callable, cleanup_args=None,
Ken'ichi Ohmichi25d5e0d2015-08-10 06:28:17 +000099 cleanup_kwargs=None):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700100 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100101
102 @param waiter_callable: callable to wait for the resource to delete
103 @param thing_id: the id of the resource to be cleaned-up
104 @param thing_id_param: the name of the id param in the waiter
105 @param cleanup_callable: method to load pass to self.addCleanup with
106 the following *cleanup_args, **cleanup_kwargs.
107 usually a delete method.
108 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900109 if cleanup_args is None:
110 cleanup_args = []
111 if cleanup_kwargs is None:
112 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100113 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
114 wait_dict = {
115 'waiter_callable': waiter_callable,
116 thing_id_param: thing_id
117 }
118 self.cleanup_waits.append(wait_dict)
119
120 def _wait_for_cleanups(self):
121 """To handle async delete actions, a list of waits is added
122 which will be iterated over as the last step of clearing the
123 cleanup queue. That way all the delete calls are made up front
124 and the tests won't succeed unless the deletes are eventually
125 successful. This is the same basic approach used in the api tests to
126 limit cleanup execution time except here it is multi-resource,
127 because of the nature of the scenario tests.
128 """
129 for wait in self.cleanup_waits:
130 waiter_callable = wait.pop('waiter_callable')
131 waiter_callable(**wait)
132
133 # ## Test functions library
134 #
135 # The create_[resource] functions only return body and discard the
136 # resp part which is not used in scenario tests
137
Yair Frieddb6c9e92014-08-06 08:53:13 +0300138 def create_keypair(self, client=None):
139 if not client:
140 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100141 name = data_utils.rand_name(self.__class__.__name__)
142 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000143 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300144 self.addCleanup(client.delete_keypair, name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100145 return body
146
147 def create_server(self, name=None, image=None, flavor=None,
148 wait_on_boot=True, wait_on_delete=True,
Ghanshyam2a180b82014-06-16 13:54:22 +0900149 create_kwargs=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100150 """Creates VM instance.
151
152 @param image: image from which to create the instance
153 @param wait_on_boot: wait for status ACTIVE before continue
154 @param wait_on_delete: force synchronous delete on cleanup
155 @param create_kwargs: additional details for instance creation
156 @return: server dict
157 """
158 if name is None:
159 name = data_utils.rand_name(self.__class__.__name__)
160 if image is None:
161 image = CONF.compute.image_ref
162 if flavor is None:
163 flavor = CONF.compute.flavor_ref
Ghanshyam2a180b82014-06-16 13:54:22 +0900164 if create_kwargs is None:
165 create_kwargs = {}
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530166 network = self.get_tenant_network()
Matthew Treinish4bbc1992015-04-07 11:13:40 -0400167 create_kwargs = fixed_network.set_networks_kwarg(network,
168 create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100169
Andrea Frittoli247058f2014-07-16 16:09:22 +0100170 LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
171 name, image, flavor)
David Kranz0fb14292015-02-11 15:55:20 -0500172 server = self.servers_client.create_server(name, image, flavor,
173 **create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100174 if wait_on_delete:
175 self.addCleanup(self.servers_client.wait_for_server_termination,
176 server['id'])
177 self.addCleanup_with_wait(
178 waiter_callable=self.servers_client.wait_for_server_termination,
179 thing_id=server['id'], thing_id_param='server_id',
180 cleanup_callable=self.delete_wrapper,
181 cleanup_args=[self.servers_client.delete_server, server['id']])
182 if wait_on_boot:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000183 waiters.wait_for_server_status(self.servers_client,
184 server_id=server['id'],
185 status='ACTIVE')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100186 # The instance retrieved on creation is missing network
187 # details, necessitating retrieval after it becomes active to
188 # ensure correct details.
Ken'ichi Ohmichi76800242015-07-03 05:12:31 +0000189 server = self.servers_client.show_server(server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100190 self.assertEqual(server['name'], name)
191 return server
192
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100193 def create_volume(self, size=None, name=None, snapshot_id=None,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100194 imageRef=None, volume_type=None, wait_on_delete=True):
195 if name is None:
196 name = data_utils.rand_name(self.__class__.__name__)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000197 volume = self.volumes_client.create_volume(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100198 size=size, display_name=name, snapshot_id=snapshot_id,
199 imageRef=imageRef, volume_type=volume_type)
Matt Riedemanne85c2702014-09-10 11:50:13 -0700200
Andrea Frittoli247058f2014-07-16 16:09:22 +0100201 if wait_on_delete:
202 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
203 volume['id'])
Matt Riedemanne85c2702014-09-10 11:50:13 -0700204 self.addCleanup(self.delete_wrapper,
205 self.volumes_client.delete_volume, volume['id'])
206 else:
207 self.addCleanup_with_wait(
208 waiter_callable=self.volumes_client.wait_for_resource_deletion,
209 thing_id=volume['id'], thing_id_param='id',
210 cleanup_callable=self.delete_wrapper,
211 cleanup_args=[self.volumes_client.delete_volume, volume['id']])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100212
213 self.assertEqual(name, volume['display_name'])
214 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
215 # The volume retrieved on creation has a non-up-to-date status.
216 # Retrieval after it becomes active ensures correct details.
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000217 volume = self.volumes_client.show_volume(volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100218 return volume
219
Yair Fried1fc32a12014-08-04 09:11:30 +0300220 def _create_loginable_secgroup_rule(self, secgroup_id=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100221 _client = self.security_groups_client
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000222 _client_rules = self.security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100223 if secgroup_id is None:
David Kranz9964b4e2015-02-06 15:45:29 -0500224 sgs = _client.list_security_groups()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100225 for sg in sgs:
226 if sg['name'] == 'default':
227 secgroup_id = sg['id']
228
229 # These rules are intended to permit inbound ssh and icmp
230 # traffic from all sources, so no group_id is provided.
231 # Setting a group_id would only permit traffic from ports
232 # belonging to the same security group.
233 rulesets = [
234 {
235 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000236 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100237 'from_port': 22,
238 'to_port': 22,
239 'cidr': '0.0.0.0/0',
240 },
241 {
242 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000243 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100244 'from_port': -1,
245 'to_port': -1,
246 'cidr': '0.0.0.0/0',
247 }
248 ]
249 rules = list()
250 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000251 sg_rule = _client_rules.create_security_group_rule(
252 parent_group_id=secgroup_id, **ruleset)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100253 self.addCleanup(self.delete_wrapper,
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000254 _client_rules.delete_security_group_rule,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100255 sg_rule['id'])
256 rules.append(sg_rule)
257 return rules
258
Yair Fried1fc32a12014-08-04 09:11:30 +0300259 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100260 # Create security group
261 sg_name = data_utils.rand_name(self.__class__.__name__)
262 sg_desc = sg_name + " description"
David Kranz9964b4e2015-02-06 15:45:29 -0500263 secgroup = self.security_groups_client.create_security_group(
Ken'ichi Ohmichi34563cc2015-07-21 00:53:17 +0000264 name=sg_name, description=sg_desc)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100265 self.assertEqual(secgroup['name'], sg_name)
266 self.assertEqual(secgroup['description'], sg_desc)
267 self.addCleanup(self.delete_wrapper,
268 self.security_groups_client.delete_security_group,
269 secgroup['id'])
270
271 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300272 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100273
274 return secgroup
275
JordanP3fe2dc32014-11-17 13:06:01 +0100276 def get_remote_client(self, server_or_ip, username=None, private_key=None,
277 log_console_of_servers=None):
278 """Get a SSH client to a remote server
279
280 @param server_or_ip a server object as returned by Tempest compute
281 client or an IP address to connect to
282 @param username name of the Linux account on the remote server
283 @param private_key the SSH private key to use
284 @param log_console_of_servers a list of server objects. Each server
285 in the list will have its console printed in the logs in case the
286 SSH connection failed to be established
287 @return a RemoteClient object
288 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100289 if isinstance(server_or_ip, six.string_types):
290 ip = server_or_ip
291 else:
Andrew Boik4a3daf12015-03-27 01:59:31 -0400292 addrs = server_or_ip['addresses'][CONF.compute.network_for_ssh]
293 try:
294 ip = (addr['addr'] for addr in addrs if
295 netaddr.valid_ipv4(addr['addr'])).next()
296 except StopIteration:
297 raise lib_exc.NotFound("No IPv4 addresses to use for SSH to "
298 "remote server.")
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700299
Andrea Frittoli247058f2014-07-16 16:09:22 +0100300 if username is None:
301 username = CONF.scenario.ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800302 # Set this with 'keypair' or others to log in with keypair or
303 # username/password.
304 if CONF.compute.ssh_auth_method == 'keypair':
305 password = None
306 if private_key is None:
307 private_key = self.keypair['private_key']
308 else:
309 password = CONF.compute.image_ssh_password
310 private_key = None
Andrea Frittoli247058f2014-07-16 16:09:22 +0100311 linux_client = remote_client.RemoteClient(ip, username,
wantwatering896300c2015-03-27 15:17:42 +0800312 pkey=private_key,
313 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100314 try:
315 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700316 except Exception as e:
317 message = ('Initializing SSH connection to %(ip)s failed. '
318 'Error: %(error)s' % {'ip': ip, 'error': e})
319 caller = misc_utils.find_test_caller()
320 if caller:
321 message = '(%s) %s' % (caller, message)
322 LOG.exception(message)
Marc Kodererb06db502015-04-30 09:31:27 +0200323 # If we don't explicitly set for which servers we want to
JordanP3fe2dc32014-11-17 13:06:01 +0100324 # log the console output then all the servers will be logged.
325 # See the definition of _log_console_output()
326 self._log_console_output(log_console_of_servers)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100327 raise
328
329 return linux_client
330
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000331 def _image_create(self, name, fmt, path,
332 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900333 if properties is None:
334 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100335 name = data_utils.rand_name('%s-' % name)
336 image_file = open(path, 'rb')
337 self.addCleanup(image_file.close)
338 params = {
339 'name': name,
340 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000341 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100342 'is_public': 'False',
343 }
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000344 params['properties'] = properties
David Kranz34f18782015-01-06 13:43:55 -0500345 image = self.image_client.create_image(**params)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100346 self.addCleanup(self.image_client.delete_image, image['id'])
347 self.assertEqual("queued", image['status'])
348 self.image_client.update_image(image['id'], data=image_file)
349 return image['id']
350
351 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300352 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100353 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
354 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
355 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300356 img_container_format = CONF.scenario.img_container_format
357 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000358 img_properties = CONF.scenario.img_properties
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300359 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000360 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300361 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000362 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100363 try:
364 self.image = self._image_create('scenario-img',
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300365 img_container_format,
366 img_path,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000367 disk_format=img_disk_format,
368 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100369 except IOError:
370 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
371 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
372 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000373 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100374 self.image = self._image_create('scenario-ami', 'ami',
375 path=ami_img_path,
376 properties=properties)
377 LOG.debug("image:%s" % self.image)
378
379 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400380 if not CONF.compute_feature_enabled.console_output:
381 LOG.debug('Console output not supported, cannot log')
382 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100383 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500384 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100385 servers = servers['servers']
386 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500387 console_output = self.servers_client.get_console_output(
David Kranzae99b9a2015-02-16 13:37:01 -0500388 server['id'], length=None).data
389 LOG.debug('Console output for %s\nbody=\n%s',
390 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100391
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000392 def _log_net_info(self, exc):
393 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300394 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000395 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000396
nithya-ganesan882595e2014-07-29 18:51:07 +0000397 def create_server_snapshot(self, server, name=None):
398 # Glance client
399 _image_client = self.image_client
400 # Compute client
401 _images_client = self.images_client
402 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000403 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000404 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000405 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500406 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000407 _image_client.wait_for_image_status(image_id, 'active')
408 self.addCleanup_with_wait(
409 waiter_callable=_image_client.wait_for_resource_deletion,
410 thing_id=image_id, thing_id_param='id',
411 cleanup_callable=self.delete_wrapper,
412 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500413 snapshot_image = _image_client.get_image_meta(image_id)
nithya-ganesan882595e2014-07-29 18:51:07 +0000414 image_name = snapshot_image['name']
415 self.assertEqual(name, image_name)
416 LOG.debug("Created snapshot image %s for server %s",
417 image_name, server['name'])
418 return snapshot_image
419
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900420 def nova_volume_attach(self):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000421 volume = self.servers_client.attach_volume(
Alexander Gubanove0634ab2015-05-25 10:28:25 +0300422 self.server['id'], self.volume['id'], '/dev/%s'
423 % CONF.compute.volume_device_name)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900424 self.assertEqual(self.volume['id'], volume['id'])
425 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
426 # Refresh the volume after the attachment
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000427 self.volume = self.volumes_client.show_volume(volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900428
429 def nova_volume_detach(self):
430 self.servers_client.detach_volume(self.server['id'], self.volume['id'])
431 self.volumes_client.wait_for_volume_status(self.volume['id'],
432 'available')
433
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000434 volume = self.volumes_client.show_volume(self.volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900435 self.assertEqual('available', volume['status'])
436
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700437 def rebuild_server(self, server_id, image=None,
438 preserve_ephemeral=False, wait=True,
439 rebuild_kwargs=None):
440 if image is None:
441 image = CONF.compute.image_ref
442
443 rebuild_kwargs = rebuild_kwargs or {}
444
445 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
446 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000447 self.servers_client.rebuild_server(
448 server_id=server_id, image_ref=image,
449 preserve_ephemeral=preserve_ephemeral,
450 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700451 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000452 waiters.wait_for_server_status(self.servers_client,
453 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700454
Steven Hardyda2a8352014-10-02 12:52:20 +0100455 def ping_ip_address(self, ip_address, should_succeed=True,
456 ping_timeout=None):
457 timeout = ping_timeout or CONF.compute.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700458 cmd = ['ping', '-c1', '-w1', ip_address]
459
460 def ping():
461 proc = subprocess.Popen(cmd,
462 stdout=subprocess.PIPE,
463 stderr=subprocess.PIPE)
464 proc.communicate()
465 return (proc.returncode == 0) == should_succeed
466
Steven Hardyda2a8352014-10-02 12:52:20 +0100467 return tempest.test.call_until_true(ping, timeout, 1)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700468
Yair Friedae0e73d2014-11-24 11:56:26 +0200469 def check_vm_connectivity(self, ip_address,
470 username=None,
471 private_key=None,
472 should_connect=True):
473 """
474 :param ip_address: server to test against
475 :param username: server's ssh username
476 :param private_key: server's ssh private key to be used
477 :param should_connect: True/False indicates positive/negative test
478 positive - attempt ping and ssh
479 negative - attempt ping and fail if succeed
480
481 :raises: AssertError if the result of the connectivity check does
482 not match the value of the should_connect param
483 """
484 if should_connect:
485 msg = "Timed out waiting for %s to become reachable" % ip_address
486 else:
487 msg = "ip address %s is reachable" % ip_address
488 self.assertTrue(self.ping_ip_address(ip_address,
489 should_succeed=should_connect),
490 msg=msg)
491 if should_connect:
492 # no need to check ssh for negative connectivity
493 self.get_remote_client(ip_address, username, private_key)
494
495 def check_public_network_connectivity(self, ip_address, username,
496 private_key, should_connect=True,
497 msg=None, servers=None):
498 # The target login is assumed to have been configured for
499 # key-based authentication by cloud-init.
500 LOG.debug('checking network connections to IP %s with user: %s' %
501 (ip_address, username))
502 try:
503 self.check_vm_connectivity(ip_address,
504 username,
505 private_key,
506 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500507 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200508 ex_msg = 'Public network connectivity check failed'
509 if msg:
510 ex_msg += ": " + msg
511 LOG.exception(ex_msg)
512 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200513 raise
514
515 def create_floating_ip(self, thing, pool_name=None):
516 """Creates a floating IP and associates to a server using
517 Nova clients
518 """
519
David Kranze4e3b412015-02-10 10:50:42 -0500520 floating_ip = self.floating_ips_client.create_floating_ip(pool_name)
Yair Friedae0e73d2014-11-24 11:56:26 +0200521 self.addCleanup(self.delete_wrapper,
522 self.floating_ips_client.delete_floating_ip,
523 floating_ip['id'])
524 self.floating_ips_client.associate_floating_ip_to_server(
525 floating_ip['ip'], thing['id'])
526 return floating_ip
527
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100528
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100529class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300530 """Base class for network scenario tests.
531 This class provide helpers for network scenario tests, using the neutron
532 API. Helpers from ancestor which use the nova network API are overridden
533 with the neutron API.
534
535 This Class also enforces using Neutron instead of novanetwork.
536 Subclassed tests will be skipped if Neutron is not enabled
537
538 """
539
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000540 credentials = ['primary', 'admin']
541
Yair Fried1fc32a12014-08-04 09:11:30 +0300542 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000543 def skip_checks(cls):
544 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100545 if not CONF.service_available.neutron:
546 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300547
548 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100549 def resource_setup(cls):
550 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300551 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300552
Yair Frieddb6c9e92014-08-06 08:53:13 +0300553 def _create_network(self, client=None, tenant_id=None,
554 namestart='network-smoke-'):
555 if not client:
556 client = self.network_client
557 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000558 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300559 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500560 result = client.create_network(name=name, tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300561 network = net_resources.DeletableNetwork(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300562 **result['network'])
563 self.assertEqual(network.name, name)
564 self.addCleanup(self.delete_wrapper, network.delete)
565 return network
566
567 def _list_networks(self, *args, **kwargs):
568 """List networks using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900569 networks_list = self.admin_manager.network_client.list_networks(
570 *args, **kwargs)
571 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300572
573 def _list_subnets(self, *args, **kwargs):
574 """List subnets using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900575 subnets_list = self.admin_manager.network_client.list_subnets(
576 *args, **kwargs)
577 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300578
579 def _list_routers(self, *args, **kwargs):
580 """List routers using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900581 routers_list = self.admin_manager.network_client.list_routers(
582 *args, **kwargs)
583 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300584
585 def _list_ports(self, *args, **kwargs):
586 """List ports using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900587 ports_list = self.admin_manager.network_client.list_ports(
588 *args, **kwargs)
589 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300590
Yair Frieddb6c9e92014-08-06 08:53:13 +0300591 def _create_subnet(self, network, client=None, namestart='subnet-smoke',
592 **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300593 """
594 Create a subnet for the given network within the cidr block
595 configured for tenant networks.
596 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300597 if not client:
598 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300599
600 def cidr_in_use(cidr, tenant_id):
601 """
602 :return True if subnet with cidr already exist in tenant
603 False else
604 """
605 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
606 return len(cidr_in_use) != 0
607
Kirill Shileev14113572014-11-21 16:58:02 +0300608 ip_version = kwargs.pop('ip_version', 4)
609
610 if ip_version == 6:
611 tenant_cidr = netaddr.IPNetwork(
612 CONF.network.tenant_network_v6_cidr)
613 num_bits = CONF.network.tenant_network_v6_mask_bits
614 else:
615 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
616 num_bits = CONF.network.tenant_network_mask_bits
617
Yair Fried1fc32a12014-08-04 09:11:30 +0300618 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300619 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300620 # Repeatedly attempt subnet creation with sequential cidr
621 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300622 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300623 str_cidr = str(subnet_cidr)
624 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
625 continue
626
627 subnet = dict(
628 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300629 network_id=network.id,
630 tenant_id=network.tenant_id,
631 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300632 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300633 **kwargs
634 )
635 try:
David Kranz34e88122014-12-11 15:24:05 -0500636 result = client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300637 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900638 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300639 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
640 if not is_overlapping_cidr:
641 raise
642 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300643 subnet = net_resources.DeletableSubnet(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300644 **result['subnet'])
645 self.assertEqual(subnet.cidr, str_cidr)
646 self.addCleanup(self.delete_wrapper, subnet.delete)
647 return subnet
648
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200649 def _create_port(self, network_id, client=None, namestart='port-quotatest',
650 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300651 if not client:
652 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300653 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500654 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300655 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200656 network_id=network_id,
657 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300658 self.assertIsNotNone(result, 'Unable to allocate port')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300659 port = net_resources.DeletablePort(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300660 **result['port'])
661 self.addCleanup(self.delete_wrapper, port.delete)
662 return port
663
Kirill Shileev14113572014-11-21 16:58:02 +0300664 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300665 ports = self._list_ports(device_id=server['id'],
666 fixed_ip=ip_addr)
667 self.assertEqual(len(ports), 1,
668 "Unable to determine which port to target.")
Kirill Shileev14113572014-11-21 16:58:02 +0300669 # it might happen here that this port has more then one ip address
670 # as in case of dual stack- when this port is created on 2 subnets
671 for ip46 in ports[0]['fixed_ips']:
672 ip = ip46['ip_address']
673 if netaddr.valid_ipv4(ip):
674 return ports[0]['id'], ip
Yair Fried1fc32a12014-08-04 09:11:30 +0300675
David Shrewsbury9bac3662014-08-07 15:07:01 -0400676 def _get_network_by_name(self, network_name):
677 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700678 self.assertNotEqual(len(net), 0,
679 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300680 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400681
Yair Friedae0e73d2014-11-24 11:56:26 +0200682 def create_floating_ip(self, thing, external_network_id=None,
683 port_id=None, client=None):
684 """Creates a floating IP and associates to a resource/port using
685 Neutron client
686 """
687 if not external_network_id:
688 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300689 if not client:
690 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300691 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300692 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
693 else:
694 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500695 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300696 floating_network_id=external_network_id,
697 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300698 tenant_id=thing['tenant_id'],
699 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300700 )
701 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300702 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300703 **result['floatingip'])
704 self.addCleanup(self.delete_wrapper, floating_ip.delete)
705 return floating_ip
706
707 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300708 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300709 floating_ip.update(port_id=port_id)
710 self.assertEqual(port_id, floating_ip.port_id)
711 return floating_ip
712
713 def _disassociate_floating_ip(self, floating_ip):
714 """
715 :param floating_ip: type DeletableFloatingIp
716 """
717 floating_ip.update(port_id=None)
718 self.assertIsNone(floating_ip.port_id)
719 return floating_ip
720
Yair Fried45f92952014-06-26 05:19:19 +0300721 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000722 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300723
724 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
725 to check status
726 :param status: target status
727 :raises: AssertionError if status doesn't match
728 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000729 def refresh():
730 floating_ip.refresh()
731 return status == floating_ip.status
732
733 tempest.test.call_until_true(refresh,
734 CONF.network.build_timeout,
735 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300736 self.assertEqual(status, floating_ip.status,
737 message="FloatingIP: {fp} is at status: {cst}. "
738 "failed to reach status: {st}"
739 .format(fp=floating_ip, cst=floating_ip.status,
740 st=status))
741 LOG.info("FloatingIP: {fp} is at status: {st}"
742 .format(fp=floating_ip, st=status))
743
Yair Fried1fc32a12014-08-04 09:11:30 +0300744 def _check_tenant_network_connectivity(self, server,
745 username,
746 private_key,
747 should_connect=True,
748 servers_for_debug=None):
749 if not CONF.network.tenant_networks_reachable:
750 msg = 'Tenant networks not configured to be reachable.'
751 LOG.info(msg)
752 return
753 # The target login is assumed to have been configured for
754 # key-based authentication by cloud-init.
755 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400756 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300757 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900758 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200759 username,
760 private_key,
761 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300762 except Exception as e:
763 LOG.exception('Tenant network connectivity check failed')
764 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000765 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300766 raise
767
768 def _check_remote_connectivity(self, source, dest, should_succeed=True):
769 """
770 check ping server via source ssh connection
771
772 :param source: RemoteClient: an ssh connection from which to ping
773 :param dest: and IP to ping against
774 :param should_succeed: boolean should ping succeed or not
775 :returns: boolean -- should_succeed == ping
776 :returns: ping is false if ping failed
777 """
778 def ping_remote():
779 try:
780 source.ping_host(dest)
Andrey Pavlov64723762015-04-29 06:24:58 +0300781 except lib_exc.SSHExecCommandFailed:
Yair Fried1fc32a12014-08-04 09:11:30 +0300782 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
783 % (dest, source.ssh_client.host))
784 return not should_succeed
785 return should_succeed
786
787 return tempest.test.call_until_true(ping_remote,
788 CONF.compute.ping_timeout,
789 1)
790
Yair Frieddb6c9e92014-08-06 08:53:13 +0300791 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300792 namestart='secgroup-smoke'):
793 if client is None:
794 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300795 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000796 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300797 secgroup = self._create_empty_security_group(namestart=namestart,
798 client=client,
799 tenant_id=tenant_id)
800
801 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900802 rules = self._create_loginable_secgroup_rule(client=client,
803 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300804 for rule in rules:
805 self.assertEqual(tenant_id, rule.tenant_id)
806 self.assertEqual(secgroup.id, rule.security_group_id)
807 return secgroup
808
Yair Frieddb6c9e92014-08-06 08:53:13 +0300809 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300810 namestart='secgroup-smoke'):
811 """Create a security group without rules.
812
813 Default rules will be created:
814 - IPv4 egress to any
815 - IPv6 egress to any
816
817 :param tenant_id: secgroup will be created in this tenant
818 :returns: DeletableSecurityGroup -- containing the secgroup created
819 """
820 if client is None:
821 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300822 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000823 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300824 sg_name = data_utils.rand_name(namestart)
825 sg_desc = sg_name + " description"
826 sg_dict = dict(name=sg_name,
827 description=sg_desc)
828 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500829 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300830 secgroup = net_resources.DeletableSecurityGroup(
831 client=client,
832 **result['security_group']
833 )
834 self.assertEqual(secgroup.name, sg_name)
835 self.assertEqual(tenant_id, secgroup.tenant_id)
836 self.assertEqual(secgroup.description, sg_desc)
837 self.addCleanup(self.delete_wrapper, secgroup.delete)
838 return secgroup
839
Yair Frieddb6c9e92014-08-06 08:53:13 +0300840 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300841 """Get default secgroup for given tenant_id.
842
843 :returns: DeletableSecurityGroup -- default secgroup for given tenant
844 """
845 if client is None:
846 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300847 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000848 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300849 sgs = [
850 sg for sg in client.list_security_groups().values()[0]
851 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
852 ]
853 msg = "No default security group for tenant %s." % (tenant_id)
854 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300855 return net_resources.DeletableSecurityGroup(client=client,
856 **sgs[0])
857
Yair Frieddb6c9e92014-08-06 08:53:13 +0300858 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300859 tenant_id=None, **kwargs):
860 """Create a rule from a dictionary of rule parameters.
861
862 Create a rule in a secgroup. if secgroup not defined will search for
863 default secgroup in tenant_id.
864
865 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300866 :param tenant_id: if secgroup not passed -- the tenant in which to
867 search for default secgroup
868 :param kwargs: a dictionary containing rule parameters:
869 for example, to allow incoming ssh:
870 rule = {
871 direction: 'ingress'
872 protocol:'tcp',
873 port_range_min: 22,
874 port_range_max: 22
875 }
876 """
877 if client is None:
878 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300879 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000880 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300881 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300882 secgroup = self._default_security_group(client=client,
883 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300884
885 ruleset = dict(security_group_id=secgroup.id,
886 tenant_id=secgroup.tenant_id)
887 ruleset.update(kwargs)
888
David Kranz34e88122014-12-11 15:24:05 -0500889 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300890 sg_rule = net_resources.DeletableSecurityGroupRule(
891 client=client,
892 **sg_rule['security_group_rule']
893 )
894 self.addCleanup(self.delete_wrapper, sg_rule.delete)
895 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
896 self.assertEqual(secgroup.id, sg_rule.security_group_id)
897
898 return sg_rule
899
900 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
901 """These rules are intended to permit inbound ssh and icmp
902 traffic from all sources, so no group_id is provided.
903 Setting a group_id would only permit traffic from ports
904 belonging to the same security group.
905 """
906
907 if client is None:
908 client = self.network_client
909 rules = []
910 rulesets = [
911 dict(
912 # ssh
913 protocol='tcp',
914 port_range_min=22,
915 port_range_max=22,
916 ),
917 dict(
918 # ping
919 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +0100920 ),
921 dict(
922 # ipv6-icmp for ping6
923 protocol='icmp',
924 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +0300925 )
926 ]
927 for ruleset in rulesets:
928 for r_direction in ['ingress', 'egress']:
929 ruleset['direction'] = r_direction
930 try:
931 sg_rule = self._create_security_group_rule(
932 client=client, secgroup=secgroup, **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +0900933 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +0300934 # if rule already exist - skip rule and continue
935 msg = 'Security group rule already exists'
936 if msg not in ex._error_string:
937 raise ex
938 else:
939 self.assertEqual(r_direction, sg_rule.direction)
940 rules.append(sg_rule)
941
942 return rules
943
944 def _ssh_to_server(self, server, private_key):
945 ssh_login = CONF.compute.image_ssh_user
946 return self.get_remote_client(server,
947 username=ssh_login,
948 private_key=private_key)
949
Yair Frieddb6c9e92014-08-06 08:53:13 +0300950 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300951 """Retrieve a router for the given tenant id.
952
953 If a public router has been configured, it will be returned.
954
955 If a public router has not been configured, but a public
956 network has, a tenant router will be created and returned that
957 routes traffic to the public network.
958 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300959 if not client:
960 client = self.network_client
961 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000962 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300963 router_id = CONF.network.public_router_id
964 network_id = CONF.network.public_network_id
965 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -0400966 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +0400967 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300968 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300969 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300970 router.set_gateway(network_id)
971 return router
972 else:
973 raise Exception("Neither of 'public_router_id' or "
974 "'public_network_id' has been defined.")
975
Yair Frieddb6c9e92014-08-06 08:53:13 +0300976 def _create_router(self, client=None, tenant_id=None,
977 namestart='router-smoke'):
978 if not client:
979 client = self.network_client
980 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000981 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300982 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500983 result = client.create_router(name=name,
984 admin_state_up=True,
985 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300986 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300987 **result['router'])
988 self.assertEqual(router.name, name)
989 self.addCleanup(self.delete_wrapper, router.delete)
990 return router
991
Alok Maurya6384bbb2014-07-13 06:44:29 -0700992 def _update_router_admin_state(self, router, admin_state_up):
993 router.update(admin_state_up=admin_state_up)
994 self.assertEqual(admin_state_up, router.admin_state_up)
995
Yair Fried413bf2d2014-11-19 17:07:11 +0200996 def create_networks(self, client=None, tenant_id=None,
997 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300998 """Create a network with a subnet connected to a router.
999
David Shrewsbury9bac3662014-08-07 15:07:01 -04001000 The baremetal driver is a special case since all nodes are
1001 on the same shared network.
1002
Yair Fried413bf2d2014-11-19 17:07:11 +02001003 :param client: network client to create resources with.
1004 :param tenant_id: id of tenant to create resources in.
1005 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001006 :returns: network, subnet, router
1007 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001008 if CONF.baremetal.driver_enabled:
1009 # NOTE(Shrews): This exception is for environments where tenant
1010 # credential isolation is available, but network separation is
1011 # not (the current baremetal case). Likely can be removed when
1012 # test account mgmt is reworked:
1013 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001014 if not CONF.compute.fixed_network_name:
1015 m = 'fixed_network_name must be specified in config'
1016 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001017 network = self._get_network_by_name(
1018 CONF.compute.fixed_network_name)
1019 router = None
1020 subnet = None
1021 else:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001022 network = self._create_network(client=client, tenant_id=tenant_id)
1023 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001024
1025 subnet_kwargs = dict(network=network, client=client)
1026 # use explicit check because empty list is a valid option
1027 if dns_nameservers is not None:
1028 subnet_kwargs['dns_nameservers'] = dns_nameservers
1029 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001030 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001031 return network, subnet, router
1032
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001033 def create_server(self, name=None, image=None, flavor=None,
1034 wait_on_boot=True, wait_on_delete=True,
1035 create_kwargs=None):
1036 vnic_type = CONF.network.port_vnic_type
1037
1038 # If vnic_type is configured create port for
1039 # every network
1040 if vnic_type:
1041 ports = []
1042 networks = []
1043 create_port_body = {'binding:vnic_type': vnic_type,
1044 'namestart': 'port-smoke'}
1045 if create_kwargs:
1046 net_client = create_kwargs.get("network_client",
1047 self.network_client)
1048
1049 # Convert security group names to security group ids
1050 # to pass to create_port
1051 if create_kwargs.get('security_groups'):
1052 security_groups = net_client.list_security_groups().get(
1053 'security_groups')
1054 sec_dict = dict([(s['name'], s['id'])
1055 for s in security_groups])
1056
1057 sec_groups_names = [s['name'] for s in create_kwargs[
1058 'security_groups']]
1059 security_groups_ids = [sec_dict[s]
1060 for s in sec_groups_names]
1061
1062 if security_groups_ids:
1063 create_port_body[
1064 'security_groups'] = security_groups_ids
1065 networks = create_kwargs.get('networks')
1066 else:
1067 net_client = self.network_client
1068 # If there are no networks passed to us we look up
1069 # for the tenant's private networks and create a port
1070 # if there is only one private network. The same behaviour
1071 # as we would expect when passing the call to the clients
1072 # with no networks
1073 if not networks:
1074 networks = net_client.list_networks(filters={
1075 'router:external': False})
1076 self.assertEqual(1, len(networks),
1077 "There is more than one"
1078 " network for the tenant")
1079 for net in networks:
1080 net_id = net['uuid']
1081 port = self._create_port(network_id=net_id,
1082 client=net_client,
1083 **create_port_body)
1084 ports.append({'port': port.id})
1085 if ports:
1086 create_kwargs['networks'] = ports
1087
1088 return super(NetworkScenarioTest, self).create_server(
1089 name=name, image=image, flavor=flavor,
1090 wait_on_boot=wait_on_boot, wait_on_delete=wait_on_delete,
1091 create_kwargs=create_kwargs)
1092
Yair Fried1fc32a12014-08-04 09:11:30 +03001093
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001094# power/provision states as of icehouse
1095class BaremetalPowerStates(object):
1096 """Possible power states of an Ironic node."""
1097 POWER_ON = 'power on'
1098 POWER_OFF = 'power off'
1099 REBOOT = 'rebooting'
1100 SUSPEND = 'suspended'
1101
1102
1103class BaremetalProvisionStates(object):
1104 """Possible provision states of an Ironic node."""
1105 NOSTATE = None
1106 INIT = 'initializing'
1107 ACTIVE = 'active'
1108 BUILDING = 'building'
1109 DEPLOYWAIT = 'wait call-back'
1110 DEPLOYING = 'deploying'
1111 DEPLOYFAIL = 'deploy failed'
1112 DEPLOYDONE = 'deploy complete'
1113 DELETING = 'deleting'
1114 DELETED = 'deleted'
1115 ERROR = 'error'
1116
1117
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001118class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001119
1120 credentials = ['primary', 'admin']
1121
Adam Gandelman4a48a602014-03-20 18:23:18 -07001122 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001123 def skip_checks(cls):
1124 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001125 if (not CONF.service_available.ironic or
1126 not CONF.baremetal.driver_enabled):
1127 msg = 'Ironic not available or Ironic compute driver not enabled'
1128 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001129
1130 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001131 def setup_clients(cls):
1132 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001133
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001134 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001135
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001136 @classmethod
1137 def resource_setup(cls):
1138 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001139 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001140 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001141
1142 def _node_state_timeout(self, node_id, state_attr,
1143 target_states, timeout=10, interval=1):
1144 if not isinstance(target_states, list):
1145 target_states = [target_states]
1146
1147 def check_state():
1148 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001149 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001150 return True
1151 return False
1152
1153 if not tempest.test.call_until_true(
1154 check_state, timeout, interval):
1155 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1156 (node_id, state_attr, target_states))
1157 raise exceptions.TimeoutException(msg)
1158
1159 def wait_provisioning_state(self, node_id, state, timeout):
1160 self._node_state_timeout(
1161 node_id=node_id, state_attr='provision_state',
1162 target_states=state, timeout=timeout)
1163
1164 def wait_power_state(self, node_id, state):
1165 self._node_state_timeout(
1166 node_id=node_id, state_attr='power_state',
1167 target_states=state, timeout=CONF.baremetal.power_timeout)
1168
1169 def wait_node(self, instance_id):
1170 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001171
Adam Gandelman4a48a602014-03-20 18:23:18 -07001172 def _get_node():
1173 node = None
1174 try:
1175 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001176 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001177 pass
1178 return node is not None
1179
1180 if not tempest.test.call_until_true(
1181 _get_node, CONF.baremetal.association_timeout, 1):
1182 msg = ('Timed out waiting to get Ironic node by instance id %s'
1183 % instance_id)
1184 raise exceptions.TimeoutException(msg)
1185
1186 def get_node(self, node_id=None, instance_id=None):
1187 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001188 _, body = self.baremetal_client.show_node(node_id)
1189 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001190 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001191 _, body = self.baremetal_client.show_node_by_instance_uuid(
1192 instance_id)
1193 if body['nodes']:
1194 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001195
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001196 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001197 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001198 _, body = self.baremetal_client.list_node_ports(node_uuid)
1199 for port in body['ports']:
1200 _, p = self.baremetal_client.show_port(port['uuid'])
1201 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001202 return ports
1203
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001204 def add_keypair(self):
1205 self.keypair = self.create_keypair()
1206
1207 def verify_connectivity(self, ip=None):
1208 if ip:
1209 dest = self.get_remote_client(ip)
1210 else:
1211 dest = self.get_remote_client(self.instance)
1212 dest.validate_authentication()
1213
1214 def boot_instance(self):
1215 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001216 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001217 }
1218 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001219 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001220
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001221 self.wait_node(self.instance['id'])
1222 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001223
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001224 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001225
1226 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001227 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001228 [BaremetalProvisionStates.DEPLOYWAIT,
1229 BaremetalProvisionStates.ACTIVE],
1230 timeout=15)
1231
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001232 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001233 BaremetalProvisionStates.ACTIVE,
1234 timeout=CONF.baremetal.active_timeout)
1235
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001236 waiters.wait_for_server_status(self.servers_client,
1237 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001238 self.node = self.get_node(instance_id=self.instance['id'])
Ken'ichi Ohmichi76800242015-07-03 05:12:31 +00001239 self.instance = self.servers_client.show_server(self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001240
1241 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001242 self.servers_client.delete_server(self.instance['id'])
1243 self.wait_power_state(self.node['uuid'],
1244 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001245 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001246 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001247 BaremetalProvisionStates.NOSTATE,
1248 timeout=CONF.baremetal.unprovision_timeout)
1249
Adam Gandelman4a48a602014-03-20 18:23:18 -07001250
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001251class EncryptionScenarioTest(ScenarioTest):
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001252 """
1253 Base class for encryption scenario tests
1254 """
1255
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001256 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001257
1258 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001259 def setup_clients(cls):
1260 super(EncryptionScenarioTest, cls).setup_clients()
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001261 cls.admin_volume_types_client = cls.os_adm.volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001262
1263 def _wait_for_volume_status(self, status):
1264 self.status_timeout(
1265 self.volume_client.volumes, self.volume.id, status)
1266
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001267 def nova_boot(self):
1268 self.keypair = self.create_keypair()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001269 create_kwargs = {'key_name': self.keypair['name']}
1270 self.server = self.create_server(image=self.image,
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001271 create_kwargs=create_kwargs)
1272
1273 def create_volume_type(self, client=None, name=None):
1274 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001275 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001276 if not name:
1277 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001278 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001279 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001280 body = client.create_volume_type(
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001281 randomized_name)
1282 self.assertIn('id', body)
1283 self.addCleanup(client.delete_volume_type, body['id'])
1284 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001285
1286 def create_encryption_type(self, client=None, type_id=None, provider=None,
1287 key_size=None, cipher=None,
1288 control_location=None):
1289 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001290 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001291 if not type_id:
1292 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001293 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001294 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001295 client.create_encryption_type(
1296 type_id, provider=provider, key_size=key_size, cipher=cipher,
1297 control_location=control_location)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001298
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001299
Chris Dent0d494112014-08-26 13:48:30 +01001300class SwiftScenarioTest(ScenarioTest):
1301 """
1302 Provide harness to do Swift scenario tests.
1303
1304 Subclasses implement the tests that use the methods provided by this
1305 class.
1306 """
1307
1308 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001309 def skip_checks(cls):
1310 super(SwiftScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001311 if not CONF.service_available.swift:
1312 skip_msg = ("%s skipped as swift is not available" %
1313 cls.__name__)
1314 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001315
1316 @classmethod
1317 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001318 cls.set_network_resources()
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001319 super(SwiftScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001320 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001321 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001322
1323 @classmethod
1324 def setup_clients(cls):
1325 super(SwiftScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001326 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001327 cls.account_client = cls.os_operator.account_client
1328 cls.container_client = cls.os_operator.container_client
1329 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001330
Chris Dentde456a12014-09-10 12:41:15 +01001331 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001332 """get swift status for our user account."""
1333 self.account_client.list_account_containers()
1334 LOG.debug('Swift status information obtained successfully')
1335
Chris Dentde456a12014-09-10 12:41:15 +01001336 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001337 name = container_name or data_utils.rand_name(
1338 'swift-scenario-container')
1339 self.container_client.create_container(name)
1340 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001341 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001342 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001343 self.addCleanup(self.delete_wrapper,
1344 self.container_client.delete_container,
1345 name)
Chris Dent0d494112014-08-26 13:48:30 +01001346 return name
1347
Chris Dentde456a12014-09-10 12:41:15 +01001348 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001349 self.container_client.delete_container(container_name)
1350 LOG.debug('Container %s deleted' % (container_name))
1351
Chris Dentde456a12014-09-10 12:41:15 +01001352 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001353 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1354 obj_data = data_utils.arbitrary_string()
1355 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001356 self.addCleanup(self.delete_wrapper,
1357 self.object_client.delete_object,
1358 container_name,
1359 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001360 return obj_name, obj_data
1361
Chris Dentde456a12014-09-10 12:41:15 +01001362 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001363 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001364 self.list_and_check_container_objects(container_name,
1365 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001366
Chris Dentde456a12014-09-10 12:41:15 +01001367 def list_and_check_container_objects(self, container_name,
1368 present_obj=None,
1369 not_present_obj=None):
Chris Dent0d494112014-08-26 13:48:30 +01001370 """
1371 List objects for a given container and assert which are present and
1372 which are not.
1373 """
Ghanshyam2a180b82014-06-16 13:54:22 +09001374 if present_obj is None:
1375 present_obj = []
1376 if not_present_obj is None:
1377 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001378 _, object_list = self.container_client.list_container_contents(
1379 container_name)
1380 if present_obj:
1381 for obj in present_obj:
1382 self.assertIn(obj, object_list)
1383 if not_present_obj:
1384 for obj in not_present_obj:
1385 self.assertNotIn(obj, object_list)
1386
Chris Dentde456a12014-09-10 12:41:15 +01001387 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001388 metadata_param = {'metadata_prefix': 'x-container-',
1389 'metadata': {'read': acl}}
1390 self.container_client.update_container_metadata(container_name,
1391 **metadata_param)
1392 resp, _ = self.container_client.list_container_metadata(container_name)
1393 self.assertEqual(resp['x-container-read'], acl)
1394
Chris Dentde456a12014-09-10 12:41:15 +01001395 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001396 _, obj = self.object_client.get_object(container_name, obj_name)
1397 self.assertEqual(obj, expected_data)