blob: 89b08421b2bd201ed4b302be49208e277b2eccfe [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)
447 self.servers_client.rebuild(server_id=server_id, image_ref=image,
448 preserve_ephemeral=preserve_ephemeral,
449 **rebuild_kwargs)
450 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000451 waiters.wait_for_server_status(self.servers_client,
452 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700453
Steven Hardyda2a8352014-10-02 12:52:20 +0100454 def ping_ip_address(self, ip_address, should_succeed=True,
455 ping_timeout=None):
456 timeout = ping_timeout or CONF.compute.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700457 cmd = ['ping', '-c1', '-w1', ip_address]
458
459 def ping():
460 proc = subprocess.Popen(cmd,
461 stdout=subprocess.PIPE,
462 stderr=subprocess.PIPE)
463 proc.communicate()
464 return (proc.returncode == 0) == should_succeed
465
Steven Hardyda2a8352014-10-02 12:52:20 +0100466 return tempest.test.call_until_true(ping, timeout, 1)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700467
Yair Friedae0e73d2014-11-24 11:56:26 +0200468 def check_vm_connectivity(self, ip_address,
469 username=None,
470 private_key=None,
471 should_connect=True):
472 """
473 :param ip_address: server to test against
474 :param username: server's ssh username
475 :param private_key: server's ssh private key to be used
476 :param should_connect: True/False indicates positive/negative test
477 positive - attempt ping and ssh
478 negative - attempt ping and fail if succeed
479
480 :raises: AssertError if the result of the connectivity check does
481 not match the value of the should_connect param
482 """
483 if should_connect:
484 msg = "Timed out waiting for %s to become reachable" % ip_address
485 else:
486 msg = "ip address %s is reachable" % ip_address
487 self.assertTrue(self.ping_ip_address(ip_address,
488 should_succeed=should_connect),
489 msg=msg)
490 if should_connect:
491 # no need to check ssh for negative connectivity
492 self.get_remote_client(ip_address, username, private_key)
493
494 def check_public_network_connectivity(self, ip_address, username,
495 private_key, should_connect=True,
496 msg=None, servers=None):
497 # The target login is assumed to have been configured for
498 # key-based authentication by cloud-init.
499 LOG.debug('checking network connections to IP %s with user: %s' %
500 (ip_address, username))
501 try:
502 self.check_vm_connectivity(ip_address,
503 username,
504 private_key,
505 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500506 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200507 ex_msg = 'Public network connectivity check failed'
508 if msg:
509 ex_msg += ": " + msg
510 LOG.exception(ex_msg)
511 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200512 raise
513
514 def create_floating_ip(self, thing, pool_name=None):
515 """Creates a floating IP and associates to a server using
516 Nova clients
517 """
518
David Kranze4e3b412015-02-10 10:50:42 -0500519 floating_ip = self.floating_ips_client.create_floating_ip(pool_name)
Yair Friedae0e73d2014-11-24 11:56:26 +0200520 self.addCleanup(self.delete_wrapper,
521 self.floating_ips_client.delete_floating_ip,
522 floating_ip['id'])
523 self.floating_ips_client.associate_floating_ip_to_server(
524 floating_ip['ip'], thing['id'])
525 return floating_ip
526
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100527
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100528class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300529 """Base class for network scenario tests.
530 This class provide helpers for network scenario tests, using the neutron
531 API. Helpers from ancestor which use the nova network API are overridden
532 with the neutron API.
533
534 This Class also enforces using Neutron instead of novanetwork.
535 Subclassed tests will be skipped if Neutron is not enabled
536
537 """
538
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000539 credentials = ['primary', 'admin']
540
Yair Fried1fc32a12014-08-04 09:11:30 +0300541 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000542 def skip_checks(cls):
543 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100544 if not CONF.service_available.neutron:
545 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300546
547 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100548 def resource_setup(cls):
549 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300550 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300551
Yair Frieddb6c9e92014-08-06 08:53:13 +0300552 def _create_network(self, client=None, tenant_id=None,
553 namestart='network-smoke-'):
554 if not client:
555 client = self.network_client
556 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000557 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300558 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500559 result = client.create_network(name=name, tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300560 network = net_resources.DeletableNetwork(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300561 **result['network'])
562 self.assertEqual(network.name, name)
563 self.addCleanup(self.delete_wrapper, network.delete)
564 return network
565
566 def _list_networks(self, *args, **kwargs):
567 """List networks using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900568 networks_list = self.admin_manager.network_client.list_networks(
569 *args, **kwargs)
570 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300571
572 def _list_subnets(self, *args, **kwargs):
573 """List subnets using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900574 subnets_list = self.admin_manager.network_client.list_subnets(
575 *args, **kwargs)
576 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300577
578 def _list_routers(self, *args, **kwargs):
579 """List routers using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900580 routers_list = self.admin_manager.network_client.list_routers(
581 *args, **kwargs)
582 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300583
584 def _list_ports(self, *args, **kwargs):
585 """List ports using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900586 ports_list = self.admin_manager.network_client.list_ports(
587 *args, **kwargs)
588 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300589
Yair Frieddb6c9e92014-08-06 08:53:13 +0300590 def _create_subnet(self, network, client=None, namestart='subnet-smoke',
591 **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300592 """
593 Create a subnet for the given network within the cidr block
594 configured for tenant networks.
595 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300596 if not client:
597 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300598
599 def cidr_in_use(cidr, tenant_id):
600 """
601 :return True if subnet with cidr already exist in tenant
602 False else
603 """
604 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
605 return len(cidr_in_use) != 0
606
Kirill Shileev14113572014-11-21 16:58:02 +0300607 ip_version = kwargs.pop('ip_version', 4)
608
609 if ip_version == 6:
610 tenant_cidr = netaddr.IPNetwork(
611 CONF.network.tenant_network_v6_cidr)
612 num_bits = CONF.network.tenant_network_v6_mask_bits
613 else:
614 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
615 num_bits = CONF.network.tenant_network_mask_bits
616
Yair Fried1fc32a12014-08-04 09:11:30 +0300617 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300618 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300619 # Repeatedly attempt subnet creation with sequential cidr
620 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300621 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300622 str_cidr = str(subnet_cidr)
623 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
624 continue
625
626 subnet = dict(
627 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300628 network_id=network.id,
629 tenant_id=network.tenant_id,
630 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300631 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300632 **kwargs
633 )
634 try:
David Kranz34e88122014-12-11 15:24:05 -0500635 result = client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300636 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900637 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300638 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
639 if not is_overlapping_cidr:
640 raise
641 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300642 subnet = net_resources.DeletableSubnet(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300643 **result['subnet'])
644 self.assertEqual(subnet.cidr, str_cidr)
645 self.addCleanup(self.delete_wrapper, subnet.delete)
646 return subnet
647
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200648 def _create_port(self, network_id, client=None, namestart='port-quotatest',
649 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300650 if not client:
651 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300652 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500653 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300654 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200655 network_id=network_id,
656 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300657 self.assertIsNotNone(result, 'Unable to allocate port')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300658 port = net_resources.DeletablePort(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300659 **result['port'])
660 self.addCleanup(self.delete_wrapper, port.delete)
661 return port
662
Kirill Shileev14113572014-11-21 16:58:02 +0300663 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300664 ports = self._list_ports(device_id=server['id'],
665 fixed_ip=ip_addr)
Kirill Shileev14113572014-11-21 16:58:02 +0300666 # it might happen here that this port has more then one ip address
667 # as in case of dual stack- when this port is created on 2 subnets
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200668 port_map = [(p["id"], fxip["ip_address"])
669 for p in ports
670 for fxip in p["fixed_ips"]
671 if netaddr.valid_ipv4(fxip["ip_address"])]
672
673 self.assertEqual(len(port_map), 1,
674 "Found multiple IPv4 addresses: %s. "
675 "Unable to determine which port to target."
676 % port_map)
677 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300678
David Shrewsbury9bac3662014-08-07 15:07:01 -0400679 def _get_network_by_name(self, network_name):
680 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700681 self.assertNotEqual(len(net), 0,
682 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300683 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400684
Yair Friedae0e73d2014-11-24 11:56:26 +0200685 def create_floating_ip(self, thing, external_network_id=None,
686 port_id=None, client=None):
687 """Creates a floating IP and associates to a resource/port using
688 Neutron client
689 """
690 if not external_network_id:
691 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300692 if not client:
693 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300694 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300695 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
696 else:
697 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500698 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300699 floating_network_id=external_network_id,
700 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300701 tenant_id=thing['tenant_id'],
702 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300703 )
704 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300705 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300706 **result['floatingip'])
707 self.addCleanup(self.delete_wrapper, floating_ip.delete)
708 return floating_ip
709
710 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300711 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300712 floating_ip.update(port_id=port_id)
713 self.assertEqual(port_id, floating_ip.port_id)
714 return floating_ip
715
716 def _disassociate_floating_ip(self, floating_ip):
717 """
718 :param floating_ip: type DeletableFloatingIp
719 """
720 floating_ip.update(port_id=None)
721 self.assertIsNone(floating_ip.port_id)
722 return floating_ip
723
Yair Fried45f92952014-06-26 05:19:19 +0300724 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000725 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300726
727 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
728 to check status
729 :param status: target status
730 :raises: AssertionError if status doesn't match
731 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000732 def refresh():
733 floating_ip.refresh()
734 return status == floating_ip.status
735
736 tempest.test.call_until_true(refresh,
737 CONF.network.build_timeout,
738 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300739 self.assertEqual(status, floating_ip.status,
740 message="FloatingIP: {fp} is at status: {cst}. "
741 "failed to reach status: {st}"
742 .format(fp=floating_ip, cst=floating_ip.status,
743 st=status))
744 LOG.info("FloatingIP: {fp} is at status: {st}"
745 .format(fp=floating_ip, st=status))
746
Yair Fried1fc32a12014-08-04 09:11:30 +0300747 def _check_tenant_network_connectivity(self, server,
748 username,
749 private_key,
750 should_connect=True,
751 servers_for_debug=None):
752 if not CONF.network.tenant_networks_reachable:
753 msg = 'Tenant networks not configured to be reachable.'
754 LOG.info(msg)
755 return
756 # The target login is assumed to have been configured for
757 # key-based authentication by cloud-init.
758 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400759 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300760 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900761 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200762 username,
763 private_key,
764 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300765 except Exception as e:
766 LOG.exception('Tenant network connectivity check failed')
767 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000768 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300769 raise
770
771 def _check_remote_connectivity(self, source, dest, should_succeed=True):
772 """
773 check ping server via source ssh connection
774
775 :param source: RemoteClient: an ssh connection from which to ping
776 :param dest: and IP to ping against
777 :param should_succeed: boolean should ping succeed or not
778 :returns: boolean -- should_succeed == ping
779 :returns: ping is false if ping failed
780 """
781 def ping_remote():
782 try:
783 source.ping_host(dest)
Andrey Pavlov64723762015-04-29 06:24:58 +0300784 except lib_exc.SSHExecCommandFailed:
Yair Fried1fc32a12014-08-04 09:11:30 +0300785 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
786 % (dest, source.ssh_client.host))
787 return not should_succeed
788 return should_succeed
789
790 return tempest.test.call_until_true(ping_remote,
791 CONF.compute.ping_timeout,
792 1)
793
Yair Frieddb6c9e92014-08-06 08:53:13 +0300794 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300795 namestart='secgroup-smoke'):
796 if client is None:
797 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300798 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000799 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300800 secgroup = self._create_empty_security_group(namestart=namestart,
801 client=client,
802 tenant_id=tenant_id)
803
804 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900805 rules = self._create_loginable_secgroup_rule(client=client,
806 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300807 for rule in rules:
808 self.assertEqual(tenant_id, rule.tenant_id)
809 self.assertEqual(secgroup.id, rule.security_group_id)
810 return secgroup
811
Yair Frieddb6c9e92014-08-06 08:53:13 +0300812 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300813 namestart='secgroup-smoke'):
814 """Create a security group without rules.
815
816 Default rules will be created:
817 - IPv4 egress to any
818 - IPv6 egress to any
819
820 :param tenant_id: secgroup will be created in this tenant
821 :returns: DeletableSecurityGroup -- containing the secgroup created
822 """
823 if client is None:
824 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300825 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000826 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300827 sg_name = data_utils.rand_name(namestart)
828 sg_desc = sg_name + " description"
829 sg_dict = dict(name=sg_name,
830 description=sg_desc)
831 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500832 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300833 secgroup = net_resources.DeletableSecurityGroup(
834 client=client,
835 **result['security_group']
836 )
837 self.assertEqual(secgroup.name, sg_name)
838 self.assertEqual(tenant_id, secgroup.tenant_id)
839 self.assertEqual(secgroup.description, sg_desc)
840 self.addCleanup(self.delete_wrapper, secgroup.delete)
841 return secgroup
842
Yair Frieddb6c9e92014-08-06 08:53:13 +0300843 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300844 """Get default secgroup for given tenant_id.
845
846 :returns: DeletableSecurityGroup -- default secgroup for given tenant
847 """
848 if client is None:
849 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300850 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000851 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300852 sgs = [
853 sg for sg in client.list_security_groups().values()[0]
854 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
855 ]
856 msg = "No default security group for tenant %s." % (tenant_id)
857 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300858 return net_resources.DeletableSecurityGroup(client=client,
859 **sgs[0])
860
Yair Frieddb6c9e92014-08-06 08:53:13 +0300861 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300862 tenant_id=None, **kwargs):
863 """Create a rule from a dictionary of rule parameters.
864
865 Create a rule in a secgroup. if secgroup not defined will search for
866 default secgroup in tenant_id.
867
868 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300869 :param tenant_id: if secgroup not passed -- the tenant in which to
870 search for default secgroup
871 :param kwargs: a dictionary containing rule parameters:
872 for example, to allow incoming ssh:
873 rule = {
874 direction: 'ingress'
875 protocol:'tcp',
876 port_range_min: 22,
877 port_range_max: 22
878 }
879 """
880 if client is None:
881 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300882 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000883 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300884 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300885 secgroup = self._default_security_group(client=client,
886 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300887
888 ruleset = dict(security_group_id=secgroup.id,
889 tenant_id=secgroup.tenant_id)
890 ruleset.update(kwargs)
891
David Kranz34e88122014-12-11 15:24:05 -0500892 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300893 sg_rule = net_resources.DeletableSecurityGroupRule(
894 client=client,
895 **sg_rule['security_group_rule']
896 )
897 self.addCleanup(self.delete_wrapper, sg_rule.delete)
898 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
899 self.assertEqual(secgroup.id, sg_rule.security_group_id)
900
901 return sg_rule
902
903 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
904 """These rules are intended to permit inbound ssh and icmp
905 traffic from all sources, so no group_id is provided.
906 Setting a group_id would only permit traffic from ports
907 belonging to the same security group.
908 """
909
910 if client is None:
911 client = self.network_client
912 rules = []
913 rulesets = [
914 dict(
915 # ssh
916 protocol='tcp',
917 port_range_min=22,
918 port_range_max=22,
919 ),
920 dict(
921 # ping
922 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +0100923 ),
924 dict(
925 # ipv6-icmp for ping6
926 protocol='icmp',
927 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +0300928 )
929 ]
930 for ruleset in rulesets:
931 for r_direction in ['ingress', 'egress']:
932 ruleset['direction'] = r_direction
933 try:
934 sg_rule = self._create_security_group_rule(
935 client=client, secgroup=secgroup, **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +0900936 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +0300937 # if rule already exist - skip rule and continue
938 msg = 'Security group rule already exists'
939 if msg not in ex._error_string:
940 raise ex
941 else:
942 self.assertEqual(r_direction, sg_rule.direction)
943 rules.append(sg_rule)
944
945 return rules
946
947 def _ssh_to_server(self, server, private_key):
948 ssh_login = CONF.compute.image_ssh_user
949 return self.get_remote_client(server,
950 username=ssh_login,
951 private_key=private_key)
952
Yair Frieddb6c9e92014-08-06 08:53:13 +0300953 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300954 """Retrieve a router for the given tenant id.
955
956 If a public router has been configured, it will be returned.
957
958 If a public router has not been configured, but a public
959 network has, a tenant router will be created and returned that
960 routes traffic to the public network.
961 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300962 if not client:
963 client = self.network_client
964 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000965 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300966 router_id = CONF.network.public_router_id
967 network_id = CONF.network.public_network_id
968 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -0400969 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +0400970 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300971 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300972 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300973 router.set_gateway(network_id)
974 return router
975 else:
976 raise Exception("Neither of 'public_router_id' or "
977 "'public_network_id' has been defined.")
978
Yair Frieddb6c9e92014-08-06 08:53:13 +0300979 def _create_router(self, client=None, tenant_id=None,
980 namestart='router-smoke'):
981 if not client:
982 client = self.network_client
983 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000984 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300985 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500986 result = client.create_router(name=name,
987 admin_state_up=True,
988 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300989 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300990 **result['router'])
991 self.assertEqual(router.name, name)
992 self.addCleanup(self.delete_wrapper, router.delete)
993 return router
994
Alok Maurya6384bbb2014-07-13 06:44:29 -0700995 def _update_router_admin_state(self, router, admin_state_up):
996 router.update(admin_state_up=admin_state_up)
997 self.assertEqual(admin_state_up, router.admin_state_up)
998
Yair Fried413bf2d2014-11-19 17:07:11 +0200999 def create_networks(self, client=None, tenant_id=None,
1000 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001001 """Create a network with a subnet connected to a router.
1002
David Shrewsbury9bac3662014-08-07 15:07:01 -04001003 The baremetal driver is a special case since all nodes are
1004 on the same shared network.
1005
Yair Fried413bf2d2014-11-19 17:07:11 +02001006 :param client: network client to create resources with.
1007 :param tenant_id: id of tenant to create resources in.
1008 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001009 :returns: network, subnet, router
1010 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001011 if CONF.baremetal.driver_enabled:
1012 # NOTE(Shrews): This exception is for environments where tenant
1013 # credential isolation is available, but network separation is
1014 # not (the current baremetal case). Likely can be removed when
1015 # test account mgmt is reworked:
1016 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001017 if not CONF.compute.fixed_network_name:
1018 m = 'fixed_network_name must be specified in config'
1019 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001020 network = self._get_network_by_name(
1021 CONF.compute.fixed_network_name)
1022 router = None
1023 subnet = None
1024 else:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001025 network = self._create_network(client=client, tenant_id=tenant_id)
1026 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001027
1028 subnet_kwargs = dict(network=network, client=client)
1029 # use explicit check because empty list is a valid option
1030 if dns_nameservers is not None:
1031 subnet_kwargs['dns_nameservers'] = dns_nameservers
1032 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001033 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001034 return network, subnet, router
1035
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001036 def create_server(self, name=None, image=None, flavor=None,
1037 wait_on_boot=True, wait_on_delete=True,
1038 create_kwargs=None):
1039 vnic_type = CONF.network.port_vnic_type
1040
1041 # If vnic_type is configured create port for
1042 # every network
1043 if vnic_type:
1044 ports = []
1045 networks = []
1046 create_port_body = {'binding:vnic_type': vnic_type,
1047 'namestart': 'port-smoke'}
1048 if create_kwargs:
1049 net_client = create_kwargs.get("network_client",
1050 self.network_client)
1051
1052 # Convert security group names to security group ids
1053 # to pass to create_port
1054 if create_kwargs.get('security_groups'):
1055 security_groups = net_client.list_security_groups().get(
1056 'security_groups')
1057 sec_dict = dict([(s['name'], s['id'])
1058 for s in security_groups])
1059
1060 sec_groups_names = [s['name'] for s in create_kwargs[
1061 'security_groups']]
1062 security_groups_ids = [sec_dict[s]
1063 for s in sec_groups_names]
1064
1065 if security_groups_ids:
1066 create_port_body[
1067 'security_groups'] = security_groups_ids
1068 networks = create_kwargs.get('networks')
1069 else:
1070 net_client = self.network_client
1071 # If there are no networks passed to us we look up
1072 # for the tenant's private networks and create a port
1073 # if there is only one private network. The same behaviour
1074 # as we would expect when passing the call to the clients
1075 # with no networks
1076 if not networks:
1077 networks = net_client.list_networks(filters={
1078 'router:external': False})
1079 self.assertEqual(1, len(networks),
1080 "There is more than one"
1081 " network for the tenant")
1082 for net in networks:
1083 net_id = net['uuid']
1084 port = self._create_port(network_id=net_id,
1085 client=net_client,
1086 **create_port_body)
1087 ports.append({'port': port.id})
1088 if ports:
1089 create_kwargs['networks'] = ports
1090
1091 return super(NetworkScenarioTest, self).create_server(
1092 name=name, image=image, flavor=flavor,
1093 wait_on_boot=wait_on_boot, wait_on_delete=wait_on_delete,
1094 create_kwargs=create_kwargs)
1095
Yair Fried1fc32a12014-08-04 09:11:30 +03001096
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001097# power/provision states as of icehouse
1098class BaremetalPowerStates(object):
1099 """Possible power states of an Ironic node."""
1100 POWER_ON = 'power on'
1101 POWER_OFF = 'power off'
1102 REBOOT = 'rebooting'
1103 SUSPEND = 'suspended'
1104
1105
1106class BaremetalProvisionStates(object):
1107 """Possible provision states of an Ironic node."""
1108 NOSTATE = None
1109 INIT = 'initializing'
1110 ACTIVE = 'active'
1111 BUILDING = 'building'
1112 DEPLOYWAIT = 'wait call-back'
1113 DEPLOYING = 'deploying'
1114 DEPLOYFAIL = 'deploy failed'
1115 DEPLOYDONE = 'deploy complete'
1116 DELETING = 'deleting'
1117 DELETED = 'deleted'
1118 ERROR = 'error'
1119
1120
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001121class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001122
1123 credentials = ['primary', 'admin']
1124
Adam Gandelman4a48a602014-03-20 18:23:18 -07001125 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001126 def skip_checks(cls):
1127 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001128 if (not CONF.service_available.ironic or
1129 not CONF.baremetal.driver_enabled):
1130 msg = 'Ironic not available or Ironic compute driver not enabled'
1131 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001132
1133 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001134 def setup_clients(cls):
1135 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001136
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001137 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001138
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001139 @classmethod
1140 def resource_setup(cls):
1141 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001142 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001143 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001144
1145 def _node_state_timeout(self, node_id, state_attr,
1146 target_states, timeout=10, interval=1):
1147 if not isinstance(target_states, list):
1148 target_states = [target_states]
1149
1150 def check_state():
1151 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001152 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001153 return True
1154 return False
1155
1156 if not tempest.test.call_until_true(
1157 check_state, timeout, interval):
1158 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1159 (node_id, state_attr, target_states))
1160 raise exceptions.TimeoutException(msg)
1161
1162 def wait_provisioning_state(self, node_id, state, timeout):
1163 self._node_state_timeout(
1164 node_id=node_id, state_attr='provision_state',
1165 target_states=state, timeout=timeout)
1166
1167 def wait_power_state(self, node_id, state):
1168 self._node_state_timeout(
1169 node_id=node_id, state_attr='power_state',
1170 target_states=state, timeout=CONF.baremetal.power_timeout)
1171
1172 def wait_node(self, instance_id):
1173 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001174
Adam Gandelman4a48a602014-03-20 18:23:18 -07001175 def _get_node():
1176 node = None
1177 try:
1178 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001179 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001180 pass
1181 return node is not None
1182
1183 if not tempest.test.call_until_true(
1184 _get_node, CONF.baremetal.association_timeout, 1):
1185 msg = ('Timed out waiting to get Ironic node by instance id %s'
1186 % instance_id)
1187 raise exceptions.TimeoutException(msg)
1188
1189 def get_node(self, node_id=None, instance_id=None):
1190 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001191 _, body = self.baremetal_client.show_node(node_id)
1192 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001193 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001194 _, body = self.baremetal_client.show_node_by_instance_uuid(
1195 instance_id)
1196 if body['nodes']:
1197 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001198
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001199 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001200 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001201 _, body = self.baremetal_client.list_node_ports(node_uuid)
1202 for port in body['ports']:
1203 _, p = self.baremetal_client.show_port(port['uuid'])
1204 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001205 return ports
1206
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001207 def add_keypair(self):
1208 self.keypair = self.create_keypair()
1209
1210 def verify_connectivity(self, ip=None):
1211 if ip:
1212 dest = self.get_remote_client(ip)
1213 else:
1214 dest = self.get_remote_client(self.instance)
1215 dest.validate_authentication()
1216
1217 def boot_instance(self):
1218 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001219 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001220 }
1221 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001222 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001223
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001224 self.wait_node(self.instance['id'])
1225 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001226
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001227 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001228
1229 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001230 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001231 [BaremetalProvisionStates.DEPLOYWAIT,
1232 BaremetalProvisionStates.ACTIVE],
1233 timeout=15)
1234
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001235 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001236 BaremetalProvisionStates.ACTIVE,
1237 timeout=CONF.baremetal.active_timeout)
1238
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001239 waiters.wait_for_server_status(self.servers_client,
1240 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001241 self.node = self.get_node(instance_id=self.instance['id'])
Ken'ichi Ohmichi76800242015-07-03 05:12:31 +00001242 self.instance = self.servers_client.show_server(self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001243
1244 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001245 self.servers_client.delete_server(self.instance['id'])
1246 self.wait_power_state(self.node['uuid'],
1247 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001248 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001249 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001250 BaremetalProvisionStates.NOSTATE,
1251 timeout=CONF.baremetal.unprovision_timeout)
1252
Adam Gandelman4a48a602014-03-20 18:23:18 -07001253
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001254class EncryptionScenarioTest(ScenarioTest):
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001255 """
1256 Base class for encryption scenario tests
1257 """
1258
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001259 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001260
1261 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001262 def setup_clients(cls):
1263 super(EncryptionScenarioTest, cls).setup_clients()
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001264 cls.admin_volume_types_client = cls.os_adm.volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001265
1266 def _wait_for_volume_status(self, status):
1267 self.status_timeout(
1268 self.volume_client.volumes, self.volume.id, status)
1269
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001270 def nova_boot(self):
1271 self.keypair = self.create_keypair()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001272 create_kwargs = {'key_name': self.keypair['name']}
1273 self.server = self.create_server(image=self.image,
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001274 create_kwargs=create_kwargs)
1275
1276 def create_volume_type(self, client=None, name=None):
1277 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001278 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001279 if not name:
1280 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001281 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001282 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001283 body = client.create_volume_type(
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001284 randomized_name)
1285 self.assertIn('id', body)
1286 self.addCleanup(client.delete_volume_type, body['id'])
1287 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001288
1289 def create_encryption_type(self, client=None, type_id=None, provider=None,
1290 key_size=None, cipher=None,
1291 control_location=None):
1292 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001293 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001294 if not type_id:
1295 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001296 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001297 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001298 client.create_encryption_type(
1299 type_id, provider=provider, key_size=key_size, cipher=cipher,
1300 control_location=control_location)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001301
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001302
Chris Dent0d494112014-08-26 13:48:30 +01001303class SwiftScenarioTest(ScenarioTest):
1304 """
1305 Provide harness to do Swift scenario tests.
1306
1307 Subclasses implement the tests that use the methods provided by this
1308 class.
1309 """
1310
1311 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001312 def skip_checks(cls):
1313 super(SwiftScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001314 if not CONF.service_available.swift:
1315 skip_msg = ("%s skipped as swift is not available" %
1316 cls.__name__)
1317 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001318
1319 @classmethod
1320 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001321 cls.set_network_resources()
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001322 super(SwiftScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001323 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001324 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001325
1326 @classmethod
1327 def setup_clients(cls):
1328 super(SwiftScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001329 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001330 cls.account_client = cls.os_operator.account_client
1331 cls.container_client = cls.os_operator.container_client
1332 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001333
Chris Dentde456a12014-09-10 12:41:15 +01001334 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001335 """get swift status for our user account."""
1336 self.account_client.list_account_containers()
1337 LOG.debug('Swift status information obtained successfully')
1338
Chris Dentde456a12014-09-10 12:41:15 +01001339 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001340 name = container_name or data_utils.rand_name(
1341 'swift-scenario-container')
1342 self.container_client.create_container(name)
1343 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001344 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001345 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001346 self.addCleanup(self.delete_wrapper,
1347 self.container_client.delete_container,
1348 name)
Chris Dent0d494112014-08-26 13:48:30 +01001349 return name
1350
Chris Dentde456a12014-09-10 12:41:15 +01001351 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001352 self.container_client.delete_container(container_name)
1353 LOG.debug('Container %s deleted' % (container_name))
1354
Chris Dentde456a12014-09-10 12:41:15 +01001355 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001356 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1357 obj_data = data_utils.arbitrary_string()
1358 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001359 self.addCleanup(self.delete_wrapper,
1360 self.object_client.delete_object,
1361 container_name,
1362 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001363 return obj_name, obj_data
1364
Chris Dentde456a12014-09-10 12:41:15 +01001365 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001366 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001367 self.list_and_check_container_objects(container_name,
1368 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001369
Chris Dentde456a12014-09-10 12:41:15 +01001370 def list_and_check_container_objects(self, container_name,
1371 present_obj=None,
1372 not_present_obj=None):
Chris Dent0d494112014-08-26 13:48:30 +01001373 """
1374 List objects for a given container and assert which are present and
1375 which are not.
1376 """
Ghanshyam2a180b82014-06-16 13:54:22 +09001377 if present_obj is None:
1378 present_obj = []
1379 if not_present_obj is None:
1380 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001381 _, object_list = self.container_client.list_container_contents(
1382 container_name)
1383 if present_obj:
1384 for obj in present_obj:
1385 self.assertIn(obj, object_list)
1386 if not_present_obj:
1387 for obj in not_present_obj:
1388 self.assertNotIn(obj, object_list)
1389
Chris Dentde456a12014-09-10 12:41:15 +01001390 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001391 metadata_param = {'metadata_prefix': 'x-container-',
1392 'metadata': {'read': acl}}
1393 self.container_client.update_container_metadata(container_name,
1394 **metadata_param)
1395 resp, _ = self.container_client.list_container_metadata(container_name)
1396 self.assertEqual(resp['x-container-read'], acl)
1397
Chris Dentde456a12014-09-10 12:41:15 +01001398 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001399 _, obj = self.object_client.get_object(container_name, obj_name)
1400 self.assertEqual(obj, expected_data)