blob: 5bff1b4aec73625620466a65b4eb9ec66a130b37 [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,
99 cleanup_kwargs=None, ignore_error=True):
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
David Kranz173f0e02015-02-06 13:47:57 -0500143 body = client.create_keypair(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
236 'ip_proto': 'tcp',
237 'from_port': 22,
238 'to_port': 22,
239 'cidr': '0.0.0.0/0',
240 },
241 {
242 # ping
243 'ip_proto': 'icmp',
244 '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 Ohmichi685cd172015-07-13 01:29:57 +0000251 sg_rule = _client_rules.create_security_group_rule(secgroup_id,
252 **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(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100264 sg_name, sg_desc)
265 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)
666 self.assertEqual(len(ports), 1,
667 "Unable to determine which port to target.")
Kirill Shileev14113572014-11-21 16:58:02 +0300668 # it might happen here that this port has more then one ip address
669 # as in case of dual stack- when this port is created on 2 subnets
670 for ip46 in ports[0]['fixed_ips']:
671 ip = ip46['ip_address']
672 if netaddr.valid_ipv4(ip):
673 return ports[0]['id'], ip
Yair Fried1fc32a12014-08-04 09:11:30 +0300674
David Shrewsbury9bac3662014-08-07 15:07:01 -0400675 def _get_network_by_name(self, network_name):
676 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700677 self.assertNotEqual(len(net), 0,
678 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300679 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400680
Yair Friedae0e73d2014-11-24 11:56:26 +0200681 def create_floating_ip(self, thing, external_network_id=None,
682 port_id=None, client=None):
683 """Creates a floating IP and associates to a resource/port using
684 Neutron client
685 """
686 if not external_network_id:
687 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300688 if not client:
689 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300690 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300691 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
692 else:
693 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500694 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300695 floating_network_id=external_network_id,
696 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300697 tenant_id=thing['tenant_id'],
698 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300699 )
700 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300701 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300702 **result['floatingip'])
703 self.addCleanup(self.delete_wrapper, floating_ip.delete)
704 return floating_ip
705
706 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300707 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300708 floating_ip.update(port_id=port_id)
709 self.assertEqual(port_id, floating_ip.port_id)
710 return floating_ip
711
712 def _disassociate_floating_ip(self, floating_ip):
713 """
714 :param floating_ip: type DeletableFloatingIp
715 """
716 floating_ip.update(port_id=None)
717 self.assertIsNone(floating_ip.port_id)
718 return floating_ip
719
Yair Fried45f92952014-06-26 05:19:19 +0300720 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000721 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300722
723 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
724 to check status
725 :param status: target status
726 :raises: AssertionError if status doesn't match
727 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000728 def refresh():
729 floating_ip.refresh()
730 return status == floating_ip.status
731
732 tempest.test.call_until_true(refresh,
733 CONF.network.build_timeout,
734 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300735 self.assertEqual(status, floating_ip.status,
736 message="FloatingIP: {fp} is at status: {cst}. "
737 "failed to reach status: {st}"
738 .format(fp=floating_ip, cst=floating_ip.status,
739 st=status))
740 LOG.info("FloatingIP: {fp} is at status: {st}"
741 .format(fp=floating_ip, st=status))
742
Yair Fried1fc32a12014-08-04 09:11:30 +0300743 def _check_tenant_network_connectivity(self, server,
744 username,
745 private_key,
746 should_connect=True,
747 servers_for_debug=None):
748 if not CONF.network.tenant_networks_reachable:
749 msg = 'Tenant networks not configured to be reachable.'
750 LOG.info(msg)
751 return
752 # The target login is assumed to have been configured for
753 # key-based authentication by cloud-init.
754 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400755 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300756 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900757 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200758 username,
759 private_key,
760 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300761 except Exception as e:
762 LOG.exception('Tenant network connectivity check failed')
763 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000764 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300765 raise
766
767 def _check_remote_connectivity(self, source, dest, should_succeed=True):
768 """
769 check ping server via source ssh connection
770
771 :param source: RemoteClient: an ssh connection from which to ping
772 :param dest: and IP to ping against
773 :param should_succeed: boolean should ping succeed or not
774 :returns: boolean -- should_succeed == ping
775 :returns: ping is false if ping failed
776 """
777 def ping_remote():
778 try:
779 source.ping_host(dest)
Andrey Pavlov64723762015-04-29 06:24:58 +0300780 except lib_exc.SSHExecCommandFailed:
Yair Fried1fc32a12014-08-04 09:11:30 +0300781 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
782 % (dest, source.ssh_client.host))
783 return not should_succeed
784 return should_succeed
785
786 return tempest.test.call_until_true(ping_remote,
787 CONF.compute.ping_timeout,
788 1)
789
Yair Frieddb6c9e92014-08-06 08:53:13 +0300790 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300791 namestart='secgroup-smoke'):
792 if client is None:
793 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300794 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000795 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300796 secgroup = self._create_empty_security_group(namestart=namestart,
797 client=client,
798 tenant_id=tenant_id)
799
800 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900801 rules = self._create_loginable_secgroup_rule(client=client,
802 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300803 for rule in rules:
804 self.assertEqual(tenant_id, rule.tenant_id)
805 self.assertEqual(secgroup.id, rule.security_group_id)
806 return secgroup
807
Yair Frieddb6c9e92014-08-06 08:53:13 +0300808 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300809 namestart='secgroup-smoke'):
810 """Create a security group without rules.
811
812 Default rules will be created:
813 - IPv4 egress to any
814 - IPv6 egress to any
815
816 :param tenant_id: secgroup will be created in this tenant
817 :returns: DeletableSecurityGroup -- containing the secgroup created
818 """
819 if client is None:
820 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300821 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000822 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300823 sg_name = data_utils.rand_name(namestart)
824 sg_desc = sg_name + " description"
825 sg_dict = dict(name=sg_name,
826 description=sg_desc)
827 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500828 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300829 secgroup = net_resources.DeletableSecurityGroup(
830 client=client,
831 **result['security_group']
832 )
833 self.assertEqual(secgroup.name, sg_name)
834 self.assertEqual(tenant_id, secgroup.tenant_id)
835 self.assertEqual(secgroup.description, sg_desc)
836 self.addCleanup(self.delete_wrapper, secgroup.delete)
837 return secgroup
838
Yair Frieddb6c9e92014-08-06 08:53:13 +0300839 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300840 """Get default secgroup for given tenant_id.
841
842 :returns: DeletableSecurityGroup -- default secgroup for given tenant
843 """
844 if client is None:
845 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300846 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000847 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300848 sgs = [
849 sg for sg in client.list_security_groups().values()[0]
850 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
851 ]
852 msg = "No default security group for tenant %s." % (tenant_id)
853 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300854 return net_resources.DeletableSecurityGroup(client=client,
855 **sgs[0])
856
Yair Frieddb6c9e92014-08-06 08:53:13 +0300857 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300858 tenant_id=None, **kwargs):
859 """Create a rule from a dictionary of rule parameters.
860
861 Create a rule in a secgroup. if secgroup not defined will search for
862 default secgroup in tenant_id.
863
864 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300865 :param tenant_id: if secgroup not passed -- the tenant in which to
866 search for default secgroup
867 :param kwargs: a dictionary containing rule parameters:
868 for example, to allow incoming ssh:
869 rule = {
870 direction: 'ingress'
871 protocol:'tcp',
872 port_range_min: 22,
873 port_range_max: 22
874 }
875 """
876 if client is None:
877 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300878 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000879 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300880 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300881 secgroup = self._default_security_group(client=client,
882 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300883
884 ruleset = dict(security_group_id=secgroup.id,
885 tenant_id=secgroup.tenant_id)
886 ruleset.update(kwargs)
887
David Kranz34e88122014-12-11 15:24:05 -0500888 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300889 sg_rule = net_resources.DeletableSecurityGroupRule(
890 client=client,
891 **sg_rule['security_group_rule']
892 )
893 self.addCleanup(self.delete_wrapper, sg_rule.delete)
894 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
895 self.assertEqual(secgroup.id, sg_rule.security_group_id)
896
897 return sg_rule
898
899 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
900 """These rules are intended to permit inbound ssh and icmp
901 traffic from all sources, so no group_id is provided.
902 Setting a group_id would only permit traffic from ports
903 belonging to the same security group.
904 """
905
906 if client is None:
907 client = self.network_client
908 rules = []
909 rulesets = [
910 dict(
911 # ssh
912 protocol='tcp',
913 port_range_min=22,
914 port_range_max=22,
915 ),
916 dict(
917 # ping
918 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +0100919 ),
920 dict(
921 # ipv6-icmp for ping6
922 protocol='icmp',
923 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +0300924 )
925 ]
926 for ruleset in rulesets:
927 for r_direction in ['ingress', 'egress']:
928 ruleset['direction'] = r_direction
929 try:
930 sg_rule = self._create_security_group_rule(
931 client=client, secgroup=secgroup, **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +0900932 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +0300933 # if rule already exist - skip rule and continue
934 msg = 'Security group rule already exists'
935 if msg not in ex._error_string:
936 raise ex
937 else:
938 self.assertEqual(r_direction, sg_rule.direction)
939 rules.append(sg_rule)
940
941 return rules
942
943 def _ssh_to_server(self, server, private_key):
944 ssh_login = CONF.compute.image_ssh_user
945 return self.get_remote_client(server,
946 username=ssh_login,
947 private_key=private_key)
948
Yair Frieddb6c9e92014-08-06 08:53:13 +0300949 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300950 """Retrieve a router for the given tenant id.
951
952 If a public router has been configured, it will be returned.
953
954 If a public router has not been configured, but a public
955 network has, a tenant router will be created and returned that
956 routes traffic to the public network.
957 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300958 if not client:
959 client = self.network_client
960 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000961 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300962 router_id = CONF.network.public_router_id
963 network_id = CONF.network.public_network_id
964 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -0400965 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +0400966 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300967 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300968 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300969 router.set_gateway(network_id)
970 return router
971 else:
972 raise Exception("Neither of 'public_router_id' or "
973 "'public_network_id' has been defined.")
974
Yair Frieddb6c9e92014-08-06 08:53:13 +0300975 def _create_router(self, client=None, tenant_id=None,
976 namestart='router-smoke'):
977 if not client:
978 client = self.network_client
979 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000980 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300981 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500982 result = client.create_router(name=name,
983 admin_state_up=True,
984 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300985 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300986 **result['router'])
987 self.assertEqual(router.name, name)
988 self.addCleanup(self.delete_wrapper, router.delete)
989 return router
990
Alok Maurya6384bbb2014-07-13 06:44:29 -0700991 def _update_router_admin_state(self, router, admin_state_up):
992 router.update(admin_state_up=admin_state_up)
993 self.assertEqual(admin_state_up, router.admin_state_up)
994
Yair Fried413bf2d2014-11-19 17:07:11 +0200995 def create_networks(self, client=None, tenant_id=None,
996 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300997 """Create a network with a subnet connected to a router.
998
David Shrewsbury9bac3662014-08-07 15:07:01 -0400999 The baremetal driver is a special case since all nodes are
1000 on the same shared network.
1001
Yair Fried413bf2d2014-11-19 17:07:11 +02001002 :param client: network client to create resources with.
1003 :param tenant_id: id of tenant to create resources in.
1004 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001005 :returns: network, subnet, router
1006 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001007 if CONF.baremetal.driver_enabled:
1008 # NOTE(Shrews): This exception is for environments where tenant
1009 # credential isolation is available, but network separation is
1010 # not (the current baremetal case). Likely can be removed when
1011 # test account mgmt is reworked:
1012 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001013 if not CONF.compute.fixed_network_name:
1014 m = 'fixed_network_name must be specified in config'
1015 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001016 network = self._get_network_by_name(
1017 CONF.compute.fixed_network_name)
1018 router = None
1019 subnet = None
1020 else:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001021 network = self._create_network(client=client, tenant_id=tenant_id)
1022 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001023
1024 subnet_kwargs = dict(network=network, client=client)
1025 # use explicit check because empty list is a valid option
1026 if dns_nameservers is not None:
1027 subnet_kwargs['dns_nameservers'] = dns_nameservers
1028 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001029 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001030 return network, subnet, router
1031
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001032 def create_server(self, name=None, image=None, flavor=None,
1033 wait_on_boot=True, wait_on_delete=True,
1034 create_kwargs=None):
1035 vnic_type = CONF.network.port_vnic_type
1036
1037 # If vnic_type is configured create port for
1038 # every network
1039 if vnic_type:
1040 ports = []
1041 networks = []
1042 create_port_body = {'binding:vnic_type': vnic_type,
1043 'namestart': 'port-smoke'}
1044 if create_kwargs:
1045 net_client = create_kwargs.get("network_client",
1046 self.network_client)
1047
1048 # Convert security group names to security group ids
1049 # to pass to create_port
1050 if create_kwargs.get('security_groups'):
1051 security_groups = net_client.list_security_groups().get(
1052 'security_groups')
1053 sec_dict = dict([(s['name'], s['id'])
1054 for s in security_groups])
1055
1056 sec_groups_names = [s['name'] for s in create_kwargs[
1057 'security_groups']]
1058 security_groups_ids = [sec_dict[s]
1059 for s in sec_groups_names]
1060
1061 if security_groups_ids:
1062 create_port_body[
1063 'security_groups'] = security_groups_ids
1064 networks = create_kwargs.get('networks')
1065 else:
1066 net_client = self.network_client
1067 # If there are no networks passed to us we look up
1068 # for the tenant's private networks and create a port
1069 # if there is only one private network. The same behaviour
1070 # as we would expect when passing the call to the clients
1071 # with no networks
1072 if not networks:
1073 networks = net_client.list_networks(filters={
1074 'router:external': False})
1075 self.assertEqual(1, len(networks),
1076 "There is more than one"
1077 " network for the tenant")
1078 for net in networks:
1079 net_id = net['uuid']
1080 port = self._create_port(network_id=net_id,
1081 client=net_client,
1082 **create_port_body)
1083 ports.append({'port': port.id})
1084 if ports:
1085 create_kwargs['networks'] = ports
1086
1087 return super(NetworkScenarioTest, self).create_server(
1088 name=name, image=image, flavor=flavor,
1089 wait_on_boot=wait_on_boot, wait_on_delete=wait_on_delete,
1090 create_kwargs=create_kwargs)
1091
Yair Fried1fc32a12014-08-04 09:11:30 +03001092
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001093# power/provision states as of icehouse
1094class BaremetalPowerStates(object):
1095 """Possible power states of an Ironic node."""
1096 POWER_ON = 'power on'
1097 POWER_OFF = 'power off'
1098 REBOOT = 'rebooting'
1099 SUSPEND = 'suspended'
1100
1101
1102class BaremetalProvisionStates(object):
1103 """Possible provision states of an Ironic node."""
1104 NOSTATE = None
1105 INIT = 'initializing'
1106 ACTIVE = 'active'
1107 BUILDING = 'building'
1108 DEPLOYWAIT = 'wait call-back'
1109 DEPLOYING = 'deploying'
1110 DEPLOYFAIL = 'deploy failed'
1111 DEPLOYDONE = 'deploy complete'
1112 DELETING = 'deleting'
1113 DELETED = 'deleted'
1114 ERROR = 'error'
1115
1116
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001117class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001118
1119 credentials = ['primary', 'admin']
1120
Adam Gandelman4a48a602014-03-20 18:23:18 -07001121 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001122 def skip_checks(cls):
1123 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001124 if (not CONF.service_available.ironic or
1125 not CONF.baremetal.driver_enabled):
1126 msg = 'Ironic not available or Ironic compute driver not enabled'
1127 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001128
1129 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001130 def setup_clients(cls):
1131 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001132
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001133 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001134
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001135 @classmethod
1136 def resource_setup(cls):
1137 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001138 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001139 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001140
1141 def _node_state_timeout(self, node_id, state_attr,
1142 target_states, timeout=10, interval=1):
1143 if not isinstance(target_states, list):
1144 target_states = [target_states]
1145
1146 def check_state():
1147 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001148 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001149 return True
1150 return False
1151
1152 if not tempest.test.call_until_true(
1153 check_state, timeout, interval):
1154 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1155 (node_id, state_attr, target_states))
1156 raise exceptions.TimeoutException(msg)
1157
1158 def wait_provisioning_state(self, node_id, state, timeout):
1159 self._node_state_timeout(
1160 node_id=node_id, state_attr='provision_state',
1161 target_states=state, timeout=timeout)
1162
1163 def wait_power_state(self, node_id, state):
1164 self._node_state_timeout(
1165 node_id=node_id, state_attr='power_state',
1166 target_states=state, timeout=CONF.baremetal.power_timeout)
1167
1168 def wait_node(self, instance_id):
1169 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001170
Adam Gandelman4a48a602014-03-20 18:23:18 -07001171 def _get_node():
1172 node = None
1173 try:
1174 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001175 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001176 pass
1177 return node is not None
1178
1179 if not tempest.test.call_until_true(
1180 _get_node, CONF.baremetal.association_timeout, 1):
1181 msg = ('Timed out waiting to get Ironic node by instance id %s'
1182 % instance_id)
1183 raise exceptions.TimeoutException(msg)
1184
1185 def get_node(self, node_id=None, instance_id=None):
1186 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001187 _, body = self.baremetal_client.show_node(node_id)
1188 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001189 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001190 _, body = self.baremetal_client.show_node_by_instance_uuid(
1191 instance_id)
1192 if body['nodes']:
1193 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001194
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001195 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001196 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001197 _, body = self.baremetal_client.list_node_ports(node_uuid)
1198 for port in body['ports']:
1199 _, p = self.baremetal_client.show_port(port['uuid'])
1200 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001201 return ports
1202
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001203 def add_keypair(self):
1204 self.keypair = self.create_keypair()
1205
1206 def verify_connectivity(self, ip=None):
1207 if ip:
1208 dest = self.get_remote_client(ip)
1209 else:
1210 dest = self.get_remote_client(self.instance)
1211 dest.validate_authentication()
1212
1213 def boot_instance(self):
1214 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001215 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001216 }
1217 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001218 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001219
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001220 self.wait_node(self.instance['id'])
1221 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001222
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001223 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001224
1225 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001226 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001227 [BaremetalProvisionStates.DEPLOYWAIT,
1228 BaremetalProvisionStates.ACTIVE],
1229 timeout=15)
1230
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001231 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001232 BaremetalProvisionStates.ACTIVE,
1233 timeout=CONF.baremetal.active_timeout)
1234
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001235 waiters.wait_for_server_status(self.servers_client,
1236 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001237 self.node = self.get_node(instance_id=self.instance['id'])
Ken'ichi Ohmichi76800242015-07-03 05:12:31 +00001238 self.instance = self.servers_client.show_server(self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001239
1240 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001241 self.servers_client.delete_server(self.instance['id'])
1242 self.wait_power_state(self.node['uuid'],
1243 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001244 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001245 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001246 BaremetalProvisionStates.NOSTATE,
1247 timeout=CONF.baremetal.unprovision_timeout)
1248
Adam Gandelman4a48a602014-03-20 18:23:18 -07001249
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001250class EncryptionScenarioTest(ScenarioTest):
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001251 """
1252 Base class for encryption scenario tests
1253 """
1254
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001255 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001256
1257 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001258 def setup_clients(cls):
1259 super(EncryptionScenarioTest, cls).setup_clients()
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001260 cls.admin_volume_types_client = cls.os_adm.volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001261
1262 def _wait_for_volume_status(self, status):
1263 self.status_timeout(
1264 self.volume_client.volumes, self.volume.id, status)
1265
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001266 def nova_boot(self):
1267 self.keypair = self.create_keypair()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001268 create_kwargs = {'key_name': self.keypair['name']}
1269 self.server = self.create_server(image=self.image,
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001270 create_kwargs=create_kwargs)
1271
1272 def create_volume_type(self, client=None, name=None):
1273 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001274 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001275 if not name:
1276 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001277 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001278 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001279 body = client.create_volume_type(
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001280 randomized_name)
1281 self.assertIn('id', body)
1282 self.addCleanup(client.delete_volume_type, body['id'])
1283 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001284
1285 def create_encryption_type(self, client=None, type_id=None, provider=None,
1286 key_size=None, cipher=None,
1287 control_location=None):
1288 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001289 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001290 if not type_id:
1291 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001292 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001293 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001294 client.create_encryption_type(
1295 type_id, provider=provider, key_size=key_size, cipher=cipher,
1296 control_location=control_location)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001297
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001298
Chris Dent0d494112014-08-26 13:48:30 +01001299class SwiftScenarioTest(ScenarioTest):
1300 """
1301 Provide harness to do Swift scenario tests.
1302
1303 Subclasses implement the tests that use the methods provided by this
1304 class.
1305 """
1306
1307 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001308 def skip_checks(cls):
1309 super(SwiftScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001310 if not CONF.service_available.swift:
1311 skip_msg = ("%s skipped as swift is not available" %
1312 cls.__name__)
1313 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001314
1315 @classmethod
1316 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001317 cls.set_network_resources()
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001318 super(SwiftScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001319 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001320 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001321
1322 @classmethod
1323 def setup_clients(cls):
1324 super(SwiftScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001325 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001326 cls.account_client = cls.os_operator.account_client
1327 cls.container_client = cls.os_operator.container_client
1328 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001329
Chris Dentde456a12014-09-10 12:41:15 +01001330 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001331 """get swift status for our user account."""
1332 self.account_client.list_account_containers()
1333 LOG.debug('Swift status information obtained successfully')
1334
Chris Dentde456a12014-09-10 12:41:15 +01001335 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001336 name = container_name or data_utils.rand_name(
1337 'swift-scenario-container')
1338 self.container_client.create_container(name)
1339 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001340 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001341 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001342 self.addCleanup(self.delete_wrapper,
1343 self.container_client.delete_container,
1344 name)
Chris Dent0d494112014-08-26 13:48:30 +01001345 return name
1346
Chris Dentde456a12014-09-10 12:41:15 +01001347 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001348 self.container_client.delete_container(container_name)
1349 LOG.debug('Container %s deleted' % (container_name))
1350
Chris Dentde456a12014-09-10 12:41:15 +01001351 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001352 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1353 obj_data = data_utils.arbitrary_string()
1354 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001355 self.addCleanup(self.delete_wrapper,
1356 self.object_client.delete_object,
1357 container_name,
1358 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001359 return obj_name, obj_data
1360
Chris Dentde456a12014-09-10 12:41:15 +01001361 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001362 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001363 self.list_and_check_container_objects(container_name,
1364 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001365
Chris Dentde456a12014-09-10 12:41:15 +01001366 def list_and_check_container_objects(self, container_name,
1367 present_obj=None,
1368 not_present_obj=None):
Chris Dent0d494112014-08-26 13:48:30 +01001369 """
1370 List objects for a given container and assert which are present and
1371 which are not.
1372 """
Ghanshyam2a180b82014-06-16 13:54:22 +09001373 if present_obj is None:
1374 present_obj = []
1375 if not_present_obj is None:
1376 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001377 _, object_list = self.container_client.list_container_contents(
1378 container_name)
1379 if present_obj:
1380 for obj in present_obj:
1381 self.assertIn(obj, object_list)
1382 if not_present_obj:
1383 for obj in not_present_obj:
1384 self.assertNotIn(obj, object_list)
1385
Chris Dentde456a12014-09-10 12:41:15 +01001386 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001387 metadata_param = {'metadata_prefix': 'x-container-',
1388 'metadata': {'read': acl}}
1389 self.container_client.update_container_metadata(container_name,
1390 **metadata_param)
1391 resp, _ = self.container_client.list_container_metadata(container_name)
1392 self.assertEqual(resp['x-container-read'], acl)
1393
Chris Dentde456a12014-09-10 12:41:15 +01001394 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001395 _, obj = self.object_client.get_object(container_name, obj_name)
1396 self.assertEqual(obj, expected_data)