blob: 03e572f86abded6b02bb0eb7f6865274b6e9648a [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
57 cls.servers_client = cls.manager.servers_client
58 cls.volumes_client = cls.manager.volumes_client
Joseph Lanouxeef192f2014-08-01 14:32:53 +000059 cls.snapshots_client = cls.manager.snapshots_client
Yair Fried1fc32a12014-08-04 09:11:30 +030060 cls.interface_client = cls.manager.interfaces_client
61 # Neutron network client
62 cls.network_client = cls.manager.network_client
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090063 # Heat client
64 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010065
Andrea Frittoli247058f2014-07-16 16:09:22 +010066 # ## Methods to handle sync and async deletes
67
68 def setUp(self):
69 super(ScenarioTest, self).setUp()
70 self.cleanup_waits = []
71 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
72 # because scenario tests in the same test class should not share
73 # resources. If resources were shared between test cases then it
74 # should be a single scenario test instead of multiples.
75
76 # NOTE(yfried): this list is cleaned at the end of test_methods and
77 # not at the end of the class
78 self.addCleanup(self._wait_for_cleanups)
79
Yair Fried1fc32a12014-08-04 09:11:30 +030080 def delete_wrapper(self, delete_thing, *args, **kwargs):
Andrea Frittoli247058f2014-07-16 16:09:22 +010081 """Ignores NotFound exceptions for delete operations.
82
Yair Fried1fc32a12014-08-04 09:11:30 +030083 @param delete_thing: delete method of a resource. method will be
84 executed as delete_thing(*args, **kwargs)
85
Andrea Frittoli247058f2014-07-16 16:09:22 +010086 """
87 try:
88 # Tempest clients return dicts, so there is no common delete
89 # method available. Using a callable instead
Yair Fried1fc32a12014-08-04 09:11:30 +030090 delete_thing(*args, **kwargs)
Masayuki Igawabfa07602015-01-20 18:47:17 +090091 except lib_exc.NotFound:
Andrea Frittoli247058f2014-07-16 16:09:22 +010092 # If the resource is already missing, mission accomplished.
93 pass
94
95 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +090096 cleanup_callable, cleanup_args=None,
97 cleanup_kwargs=None, ignore_error=True):
Adam Gandelmanc78c7572014-08-28 18:38:55 -070098 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +010099
100 @param waiter_callable: callable to wait for the resource to delete
101 @param thing_id: the id of the resource to be cleaned-up
102 @param thing_id_param: the name of the id param in the waiter
103 @param cleanup_callable: method to load pass to self.addCleanup with
104 the following *cleanup_args, **cleanup_kwargs.
105 usually a delete method.
106 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900107 if cleanup_args is None:
108 cleanup_args = []
109 if cleanup_kwargs is None:
110 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100111 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
112 wait_dict = {
113 'waiter_callable': waiter_callable,
114 thing_id_param: thing_id
115 }
116 self.cleanup_waits.append(wait_dict)
117
118 def _wait_for_cleanups(self):
119 """To handle async delete actions, a list of waits is added
120 which will be iterated over as the last step of clearing the
121 cleanup queue. That way all the delete calls are made up front
122 and the tests won't succeed unless the deletes are eventually
123 successful. This is the same basic approach used in the api tests to
124 limit cleanup execution time except here it is multi-resource,
125 because of the nature of the scenario tests.
126 """
127 for wait in self.cleanup_waits:
128 waiter_callable = wait.pop('waiter_callable')
129 waiter_callable(**wait)
130
131 # ## Test functions library
132 #
133 # The create_[resource] functions only return body and discard the
134 # resp part which is not used in scenario tests
135
Yair Frieddb6c9e92014-08-06 08:53:13 +0300136 def create_keypair(self, client=None):
137 if not client:
138 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100139 name = data_utils.rand_name(self.__class__.__name__)
140 # We don't need to create a keypair by pubkey in scenario
David Kranz173f0e02015-02-06 13:47:57 -0500141 body = client.create_keypair(name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300142 self.addCleanup(client.delete_keypair, name)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100143 return body
144
145 def create_server(self, name=None, image=None, flavor=None,
146 wait_on_boot=True, wait_on_delete=True,
Ghanshyam2a180b82014-06-16 13:54:22 +0900147 create_kwargs=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100148 """Creates VM instance.
149
150 @param image: image from which to create the instance
151 @param wait_on_boot: wait for status ACTIVE before continue
152 @param wait_on_delete: force synchronous delete on cleanup
153 @param create_kwargs: additional details for instance creation
154 @return: server dict
155 """
156 if name is None:
157 name = data_utils.rand_name(self.__class__.__name__)
158 if image is None:
159 image = CONF.compute.image_ref
160 if flavor is None:
161 flavor = CONF.compute.flavor_ref
Ghanshyam2a180b82014-06-16 13:54:22 +0900162 if create_kwargs is None:
163 create_kwargs = {}
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530164 network = self.get_tenant_network()
Matthew Treinish4bbc1992015-04-07 11:13:40 -0400165 create_kwargs = fixed_network.set_networks_kwarg(network,
166 create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100167
Andrea Frittoli247058f2014-07-16 16:09:22 +0100168 LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
169 name, image, flavor)
David Kranz0fb14292015-02-11 15:55:20 -0500170 server = self.servers_client.create_server(name, image, flavor,
171 **create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100172 if wait_on_delete:
173 self.addCleanup(self.servers_client.wait_for_server_termination,
174 server['id'])
175 self.addCleanup_with_wait(
176 waiter_callable=self.servers_client.wait_for_server_termination,
177 thing_id=server['id'], thing_id_param='server_id',
178 cleanup_callable=self.delete_wrapper,
179 cleanup_args=[self.servers_client.delete_server, server['id']])
180 if wait_on_boot:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000181 waiters.wait_for_server_status(self.servers_client,
182 server_id=server['id'],
183 status='ACTIVE')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100184 # The instance retrieved on creation is missing network
185 # details, necessitating retrieval after it becomes active to
186 # ensure correct details.
Ken'ichi Ohmichi76800242015-07-03 05:12:31 +0000187 server = self.servers_client.show_server(server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100188 self.assertEqual(server['name'], name)
189 return server
190
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100191 def create_volume(self, size=None, name=None, snapshot_id=None,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100192 imageRef=None, volume_type=None, wait_on_delete=True):
193 if name is None:
194 name = data_utils.rand_name(self.__class__.__name__)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000195 volume = self.volumes_client.create_volume(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100196 size=size, display_name=name, snapshot_id=snapshot_id,
197 imageRef=imageRef, volume_type=volume_type)
Matt Riedemanne85c2702014-09-10 11:50:13 -0700198
Andrea Frittoli247058f2014-07-16 16:09:22 +0100199 if wait_on_delete:
200 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
201 volume['id'])
Matt Riedemanne85c2702014-09-10 11:50:13 -0700202 self.addCleanup(self.delete_wrapper,
203 self.volumes_client.delete_volume, volume['id'])
204 else:
205 self.addCleanup_with_wait(
206 waiter_callable=self.volumes_client.wait_for_resource_deletion,
207 thing_id=volume['id'], thing_id_param='id',
208 cleanup_callable=self.delete_wrapper,
209 cleanup_args=[self.volumes_client.delete_volume, volume['id']])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100210
211 self.assertEqual(name, volume['display_name'])
212 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
213 # The volume retrieved on creation has a non-up-to-date status.
214 # Retrieval after it becomes active ensures correct details.
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000215 volume = self.volumes_client.show_volume(volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100216 return volume
217
Yair Fried1fc32a12014-08-04 09:11:30 +0300218 def _create_loginable_secgroup_rule(self, secgroup_id=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100219 _client = self.security_groups_client
220 if secgroup_id is None:
David Kranz9964b4e2015-02-06 15:45:29 -0500221 sgs = _client.list_security_groups()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100222 for sg in sgs:
223 if sg['name'] == 'default':
224 secgroup_id = sg['id']
225
226 # These rules are intended to permit inbound ssh and icmp
227 # traffic from all sources, so no group_id is provided.
228 # Setting a group_id would only permit traffic from ports
229 # belonging to the same security group.
230 rulesets = [
231 {
232 # ssh
233 'ip_proto': 'tcp',
234 'from_port': 22,
235 'to_port': 22,
236 'cidr': '0.0.0.0/0',
237 },
238 {
239 # ping
240 'ip_proto': 'icmp',
241 'from_port': -1,
242 'to_port': -1,
243 'cidr': '0.0.0.0/0',
244 }
245 ]
246 rules = list()
247 for ruleset in rulesets:
David Kranz9964b4e2015-02-06 15:45:29 -0500248 sg_rule = _client.create_security_group_rule(secgroup_id,
249 **ruleset)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100250 self.addCleanup(self.delete_wrapper,
251 _client.delete_security_group_rule,
252 sg_rule['id'])
253 rules.append(sg_rule)
254 return rules
255
Yair Fried1fc32a12014-08-04 09:11:30 +0300256 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100257 # Create security group
258 sg_name = data_utils.rand_name(self.__class__.__name__)
259 sg_desc = sg_name + " description"
David Kranz9964b4e2015-02-06 15:45:29 -0500260 secgroup = self.security_groups_client.create_security_group(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100261 sg_name, sg_desc)
262 self.assertEqual(secgroup['name'], sg_name)
263 self.assertEqual(secgroup['description'], sg_desc)
264 self.addCleanup(self.delete_wrapper,
265 self.security_groups_client.delete_security_group,
266 secgroup['id'])
267
268 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300269 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100270
271 return secgroup
272
JordanP3fe2dc32014-11-17 13:06:01 +0100273 def get_remote_client(self, server_or_ip, username=None, private_key=None,
274 log_console_of_servers=None):
275 """Get a SSH client to a remote server
276
277 @param server_or_ip a server object as returned by Tempest compute
278 client or an IP address to connect to
279 @param username name of the Linux account on the remote server
280 @param private_key the SSH private key to use
281 @param log_console_of_servers a list of server objects. Each server
282 in the list will have its console printed in the logs in case the
283 SSH connection failed to be established
284 @return a RemoteClient object
285 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100286 if isinstance(server_or_ip, six.string_types):
287 ip = server_or_ip
288 else:
Andrew Boik4a3daf12015-03-27 01:59:31 -0400289 addrs = server_or_ip['addresses'][CONF.compute.network_for_ssh]
290 try:
291 ip = (addr['addr'] for addr in addrs if
292 netaddr.valid_ipv4(addr['addr'])).next()
293 except StopIteration:
294 raise lib_exc.NotFound("No IPv4 addresses to use for SSH to "
295 "remote server.")
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700296
Andrea Frittoli247058f2014-07-16 16:09:22 +0100297 if username is None:
298 username = CONF.scenario.ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800299 # Set this with 'keypair' or others to log in with keypair or
300 # username/password.
301 if CONF.compute.ssh_auth_method == 'keypair':
302 password = None
303 if private_key is None:
304 private_key = self.keypair['private_key']
305 else:
306 password = CONF.compute.image_ssh_password
307 private_key = None
Andrea Frittoli247058f2014-07-16 16:09:22 +0100308 linux_client = remote_client.RemoteClient(ip, username,
wantwatering896300c2015-03-27 15:17:42 +0800309 pkey=private_key,
310 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100311 try:
312 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700313 except Exception as e:
314 message = ('Initializing SSH connection to %(ip)s failed. '
315 'Error: %(error)s' % {'ip': ip, 'error': e})
316 caller = misc_utils.find_test_caller()
317 if caller:
318 message = '(%s) %s' % (caller, message)
319 LOG.exception(message)
Marc Kodererb06db502015-04-30 09:31:27 +0200320 # If we don't explicitly set for which servers we want to
JordanP3fe2dc32014-11-17 13:06:01 +0100321 # log the console output then all the servers will be logged.
322 # See the definition of _log_console_output()
323 self._log_console_output(log_console_of_servers)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100324 raise
325
326 return linux_client
327
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000328 def _image_create(self, name, fmt, path,
329 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900330 if properties is None:
331 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100332 name = data_utils.rand_name('%s-' % name)
333 image_file = open(path, 'rb')
334 self.addCleanup(image_file.close)
335 params = {
336 'name': name,
337 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000338 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100339 'is_public': 'False',
340 }
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000341 params['properties'] = properties
David Kranz34f18782015-01-06 13:43:55 -0500342 image = self.image_client.create_image(**params)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100343 self.addCleanup(self.image_client.delete_image, image['id'])
344 self.assertEqual("queued", image['status'])
345 self.image_client.update_image(image['id'], data=image_file)
346 return image['id']
347
348 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300349 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100350 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
351 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
352 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300353 img_container_format = CONF.scenario.img_container_format
354 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000355 img_properties = CONF.scenario.img_properties
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300356 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000357 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300358 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000359 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100360 try:
361 self.image = self._image_create('scenario-img',
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300362 img_container_format,
363 img_path,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000364 disk_format=img_disk_format,
365 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100366 except IOError:
367 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
368 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
369 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000370 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100371 self.image = self._image_create('scenario-ami', 'ami',
372 path=ami_img_path,
373 properties=properties)
374 LOG.debug("image:%s" % self.image)
375
376 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400377 if not CONF.compute_feature_enabled.console_output:
378 LOG.debug('Console output not supported, cannot log')
379 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100380 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500381 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100382 servers = servers['servers']
383 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500384 console_output = self.servers_client.get_console_output(
David Kranzae99b9a2015-02-16 13:37:01 -0500385 server['id'], length=None).data
386 LOG.debug('Console output for %s\nbody=\n%s',
387 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100388
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000389 def _log_net_info(self, exc):
390 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300391 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000392 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000393
nithya-ganesan882595e2014-07-29 18:51:07 +0000394 def create_server_snapshot(self, server, name=None):
395 # Glance client
396 _image_client = self.image_client
397 # Compute client
398 _images_client = self.images_client
399 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000400 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000401 LOG.debug("Creating a snapshot image for server: %s", server['name'])
David Kranza5299eb2015-01-15 17:24:05 -0500402 image = _images_client.create_image(server['id'], name)
403 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000404 _image_client.wait_for_image_status(image_id, 'active')
405 self.addCleanup_with_wait(
406 waiter_callable=_image_client.wait_for_resource_deletion,
407 thing_id=image_id, thing_id_param='id',
408 cleanup_callable=self.delete_wrapper,
409 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500410 snapshot_image = _image_client.get_image_meta(image_id)
nithya-ganesan882595e2014-07-29 18:51:07 +0000411 image_name = snapshot_image['name']
412 self.assertEqual(name, image_name)
413 LOG.debug("Created snapshot image %s for server %s",
414 image_name, server['name'])
415 return snapshot_image
416
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900417 def nova_volume_attach(self):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000418 volume = self.servers_client.attach_volume(
Alexander Gubanove0634ab2015-05-25 10:28:25 +0300419 self.server['id'], self.volume['id'], '/dev/%s'
420 % CONF.compute.volume_device_name)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900421 self.assertEqual(self.volume['id'], volume['id'])
422 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
423 # Refresh the volume after the attachment
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000424 self.volume = self.volumes_client.show_volume(volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900425
426 def nova_volume_detach(self):
427 self.servers_client.detach_volume(self.server['id'], self.volume['id'])
428 self.volumes_client.wait_for_volume_status(self.volume['id'],
429 'available')
430
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000431 volume = self.volumes_client.show_volume(self.volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900432 self.assertEqual('available', volume['status'])
433
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700434 def rebuild_server(self, server_id, image=None,
435 preserve_ephemeral=False, wait=True,
436 rebuild_kwargs=None):
437 if image is None:
438 image = CONF.compute.image_ref
439
440 rebuild_kwargs = rebuild_kwargs or {}
441
442 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
443 server_id, image, preserve_ephemeral)
444 self.servers_client.rebuild(server_id=server_id, image_ref=image,
445 preserve_ephemeral=preserve_ephemeral,
446 **rebuild_kwargs)
447 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000448 waiters.wait_for_server_status(self.servers_client,
449 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700450
Steven Hardyda2a8352014-10-02 12:52:20 +0100451 def ping_ip_address(self, ip_address, should_succeed=True,
452 ping_timeout=None):
453 timeout = ping_timeout or CONF.compute.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700454 cmd = ['ping', '-c1', '-w1', ip_address]
455
456 def ping():
457 proc = subprocess.Popen(cmd,
458 stdout=subprocess.PIPE,
459 stderr=subprocess.PIPE)
460 proc.communicate()
461 return (proc.returncode == 0) == should_succeed
462
Steven Hardyda2a8352014-10-02 12:52:20 +0100463 return tempest.test.call_until_true(ping, timeout, 1)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700464
Yair Friedae0e73d2014-11-24 11:56:26 +0200465 def check_vm_connectivity(self, ip_address,
466 username=None,
467 private_key=None,
468 should_connect=True):
469 """
470 :param ip_address: server to test against
471 :param username: server's ssh username
472 :param private_key: server's ssh private key to be used
473 :param should_connect: True/False indicates positive/negative test
474 positive - attempt ping and ssh
475 negative - attempt ping and fail if succeed
476
477 :raises: AssertError if the result of the connectivity check does
478 not match the value of the should_connect param
479 """
480 if should_connect:
481 msg = "Timed out waiting for %s to become reachable" % ip_address
482 else:
483 msg = "ip address %s is reachable" % ip_address
484 self.assertTrue(self.ping_ip_address(ip_address,
485 should_succeed=should_connect),
486 msg=msg)
487 if should_connect:
488 # no need to check ssh for negative connectivity
489 self.get_remote_client(ip_address, username, private_key)
490
491 def check_public_network_connectivity(self, ip_address, username,
492 private_key, should_connect=True,
493 msg=None, servers=None):
494 # The target login is assumed to have been configured for
495 # key-based authentication by cloud-init.
496 LOG.debug('checking network connections to IP %s with user: %s' %
497 (ip_address, username))
498 try:
499 self.check_vm_connectivity(ip_address,
500 username,
501 private_key,
502 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500503 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200504 ex_msg = 'Public network connectivity check failed'
505 if msg:
506 ex_msg += ": " + msg
507 LOG.exception(ex_msg)
508 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200509 raise
510
511 def create_floating_ip(self, thing, pool_name=None):
512 """Creates a floating IP and associates to a server using
513 Nova clients
514 """
515
David Kranze4e3b412015-02-10 10:50:42 -0500516 floating_ip = self.floating_ips_client.create_floating_ip(pool_name)
Yair Friedae0e73d2014-11-24 11:56:26 +0200517 self.addCleanup(self.delete_wrapper,
518 self.floating_ips_client.delete_floating_ip,
519 floating_ip['id'])
520 self.floating_ips_client.associate_floating_ip_to_server(
521 floating_ip['ip'], thing['id'])
522 return floating_ip
523
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100524
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100525class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300526 """Base class for network scenario tests.
527 This class provide helpers for network scenario tests, using the neutron
528 API. Helpers from ancestor which use the nova network API are overridden
529 with the neutron API.
530
531 This Class also enforces using Neutron instead of novanetwork.
532 Subclassed tests will be skipped if Neutron is not enabled
533
534 """
535
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000536 credentials = ['primary', 'admin']
537
Yair Fried1fc32a12014-08-04 09:11:30 +0300538 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000539 def skip_checks(cls):
540 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100541 if not CONF.service_available.neutron:
542 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300543
544 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100545 def resource_setup(cls):
546 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300547 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300548
Yair Frieddb6c9e92014-08-06 08:53:13 +0300549 def _create_network(self, client=None, tenant_id=None,
550 namestart='network-smoke-'):
551 if not client:
552 client = self.network_client
553 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000554 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300555 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500556 result = client.create_network(name=name, tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300557 network = net_resources.DeletableNetwork(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300558 **result['network'])
559 self.assertEqual(network.name, name)
560 self.addCleanup(self.delete_wrapper, network.delete)
561 return network
562
563 def _list_networks(self, *args, **kwargs):
564 """List networks using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900565 networks_list = self.admin_manager.network_client.list_networks(
566 *args, **kwargs)
567 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300568
569 def _list_subnets(self, *args, **kwargs):
570 """List subnets using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900571 subnets_list = self.admin_manager.network_client.list_subnets(
572 *args, **kwargs)
573 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300574
575 def _list_routers(self, *args, **kwargs):
576 """List routers using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900577 routers_list = self.admin_manager.network_client.list_routers(
578 *args, **kwargs)
579 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300580
581 def _list_ports(self, *args, **kwargs):
582 """List ports using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900583 ports_list = self.admin_manager.network_client.list_ports(
584 *args, **kwargs)
585 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300586
Yair Frieddb6c9e92014-08-06 08:53:13 +0300587 def _create_subnet(self, network, client=None, namestart='subnet-smoke',
588 **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300589 """
590 Create a subnet for the given network within the cidr block
591 configured for tenant networks.
592 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300593 if not client:
594 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300595
596 def cidr_in_use(cidr, tenant_id):
597 """
598 :return True if subnet with cidr already exist in tenant
599 False else
600 """
601 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
602 return len(cidr_in_use) != 0
603
Kirill Shileev14113572014-11-21 16:58:02 +0300604 ip_version = kwargs.pop('ip_version', 4)
605
606 if ip_version == 6:
607 tenant_cidr = netaddr.IPNetwork(
608 CONF.network.tenant_network_v6_cidr)
609 num_bits = CONF.network.tenant_network_v6_mask_bits
610 else:
611 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
612 num_bits = CONF.network.tenant_network_mask_bits
613
Yair Fried1fc32a12014-08-04 09:11:30 +0300614 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300615 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300616 # Repeatedly attempt subnet creation with sequential cidr
617 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300618 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300619 str_cidr = str(subnet_cidr)
620 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
621 continue
622
623 subnet = dict(
624 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300625 network_id=network.id,
626 tenant_id=network.tenant_id,
627 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300628 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300629 **kwargs
630 )
631 try:
David Kranz34e88122014-12-11 15:24:05 -0500632 result = client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300633 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900634 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300635 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
636 if not is_overlapping_cidr:
637 raise
638 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300639 subnet = net_resources.DeletableSubnet(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300640 **result['subnet'])
641 self.assertEqual(subnet.cidr, str_cidr)
642 self.addCleanup(self.delete_wrapper, subnet.delete)
643 return subnet
644
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200645 def _create_port(self, network_id, client=None, namestart='port-quotatest',
646 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300647 if not client:
648 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300649 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500650 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300651 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200652 network_id=network_id,
653 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300654 self.assertIsNotNone(result, 'Unable to allocate port')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300655 port = net_resources.DeletablePort(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300656 **result['port'])
657 self.addCleanup(self.delete_wrapper, port.delete)
658 return port
659
Kirill Shileev14113572014-11-21 16:58:02 +0300660 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300661 ports = self._list_ports(device_id=server['id'],
662 fixed_ip=ip_addr)
663 self.assertEqual(len(ports), 1,
664 "Unable to determine which port to target.")
Kirill Shileev14113572014-11-21 16:58:02 +0300665 # it might happen here that this port has more then one ip address
666 # as in case of dual stack- when this port is created on 2 subnets
667 for ip46 in ports[0]['fixed_ips']:
668 ip = ip46['ip_address']
669 if netaddr.valid_ipv4(ip):
670 return ports[0]['id'], ip
Yair Fried1fc32a12014-08-04 09:11:30 +0300671
David Shrewsbury9bac3662014-08-07 15:07:01 -0400672 def _get_network_by_name(self, network_name):
673 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700674 self.assertNotEqual(len(net), 0,
675 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300676 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400677
Yair Friedae0e73d2014-11-24 11:56:26 +0200678 def create_floating_ip(self, thing, external_network_id=None,
679 port_id=None, client=None):
680 """Creates a floating IP and associates to a resource/port using
681 Neutron client
682 """
683 if not external_network_id:
684 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300685 if not client:
686 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300687 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300688 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
689 else:
690 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500691 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300692 floating_network_id=external_network_id,
693 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300694 tenant_id=thing['tenant_id'],
695 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300696 )
697 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300698 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300699 **result['floatingip'])
700 self.addCleanup(self.delete_wrapper, floating_ip.delete)
701 return floating_ip
702
703 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300704 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300705 floating_ip.update(port_id=port_id)
706 self.assertEqual(port_id, floating_ip.port_id)
707 return floating_ip
708
709 def _disassociate_floating_ip(self, floating_ip):
710 """
711 :param floating_ip: type DeletableFloatingIp
712 """
713 floating_ip.update(port_id=None)
714 self.assertIsNone(floating_ip.port_id)
715 return floating_ip
716
Yair Fried45f92952014-06-26 05:19:19 +0300717 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000718 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300719
720 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
721 to check status
722 :param status: target status
723 :raises: AssertionError if status doesn't match
724 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000725 def refresh():
726 floating_ip.refresh()
727 return status == floating_ip.status
728
729 tempest.test.call_until_true(refresh,
730 CONF.network.build_timeout,
731 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300732 self.assertEqual(status, floating_ip.status,
733 message="FloatingIP: {fp} is at status: {cst}. "
734 "failed to reach status: {st}"
735 .format(fp=floating_ip, cst=floating_ip.status,
736 st=status))
737 LOG.info("FloatingIP: {fp} is at status: {st}"
738 .format(fp=floating_ip, st=status))
739
Yair Fried1fc32a12014-08-04 09:11:30 +0300740 def _check_tenant_network_connectivity(self, server,
741 username,
742 private_key,
743 should_connect=True,
744 servers_for_debug=None):
745 if not CONF.network.tenant_networks_reachable:
746 msg = 'Tenant networks not configured to be reachable.'
747 LOG.info(msg)
748 return
749 # The target login is assumed to have been configured for
750 # key-based authentication by cloud-init.
751 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400752 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300753 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900754 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200755 username,
756 private_key,
757 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300758 except Exception as e:
759 LOG.exception('Tenant network connectivity check failed')
760 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000761 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300762 raise
763
764 def _check_remote_connectivity(self, source, dest, should_succeed=True):
765 """
766 check ping server via source ssh connection
767
768 :param source: RemoteClient: an ssh connection from which to ping
769 :param dest: and IP to ping against
770 :param should_succeed: boolean should ping succeed or not
771 :returns: boolean -- should_succeed == ping
772 :returns: ping is false if ping failed
773 """
774 def ping_remote():
775 try:
776 source.ping_host(dest)
Andrey Pavlov64723762015-04-29 06:24:58 +0300777 except lib_exc.SSHExecCommandFailed:
Yair Fried1fc32a12014-08-04 09:11:30 +0300778 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
779 % (dest, source.ssh_client.host))
780 return not should_succeed
781 return should_succeed
782
783 return tempest.test.call_until_true(ping_remote,
784 CONF.compute.ping_timeout,
785 1)
786
Yair Frieddb6c9e92014-08-06 08:53:13 +0300787 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300788 namestart='secgroup-smoke'):
789 if client is None:
790 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300791 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000792 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300793 secgroup = self._create_empty_security_group(namestart=namestart,
794 client=client,
795 tenant_id=tenant_id)
796
797 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900798 rules = self._create_loginable_secgroup_rule(client=client,
799 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300800 for rule in rules:
801 self.assertEqual(tenant_id, rule.tenant_id)
802 self.assertEqual(secgroup.id, rule.security_group_id)
803 return secgroup
804
Yair Frieddb6c9e92014-08-06 08:53:13 +0300805 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300806 namestart='secgroup-smoke'):
807 """Create a security group without rules.
808
809 Default rules will be created:
810 - IPv4 egress to any
811 - IPv6 egress to any
812
813 :param tenant_id: secgroup will be created in this tenant
814 :returns: DeletableSecurityGroup -- containing the secgroup created
815 """
816 if client is None:
817 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300818 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000819 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300820 sg_name = data_utils.rand_name(namestart)
821 sg_desc = sg_name + " description"
822 sg_dict = dict(name=sg_name,
823 description=sg_desc)
824 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500825 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300826 secgroup = net_resources.DeletableSecurityGroup(
827 client=client,
828 **result['security_group']
829 )
830 self.assertEqual(secgroup.name, sg_name)
831 self.assertEqual(tenant_id, secgroup.tenant_id)
832 self.assertEqual(secgroup.description, sg_desc)
833 self.addCleanup(self.delete_wrapper, secgroup.delete)
834 return secgroup
835
Yair Frieddb6c9e92014-08-06 08:53:13 +0300836 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300837 """Get default secgroup for given tenant_id.
838
839 :returns: DeletableSecurityGroup -- default secgroup for given tenant
840 """
841 if client is None:
842 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300843 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000844 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300845 sgs = [
846 sg for sg in client.list_security_groups().values()[0]
847 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
848 ]
849 msg = "No default security group for tenant %s." % (tenant_id)
850 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300851 return net_resources.DeletableSecurityGroup(client=client,
852 **sgs[0])
853
Yair Frieddb6c9e92014-08-06 08:53:13 +0300854 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300855 tenant_id=None, **kwargs):
856 """Create a rule from a dictionary of rule parameters.
857
858 Create a rule in a secgroup. if secgroup not defined will search for
859 default secgroup in tenant_id.
860
861 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300862 :param tenant_id: if secgroup not passed -- the tenant in which to
863 search for default secgroup
864 :param kwargs: a dictionary containing rule parameters:
865 for example, to allow incoming ssh:
866 rule = {
867 direction: 'ingress'
868 protocol:'tcp',
869 port_range_min: 22,
870 port_range_max: 22
871 }
872 """
873 if client is None:
874 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300875 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000876 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300877 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300878 secgroup = self._default_security_group(client=client,
879 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300880
881 ruleset = dict(security_group_id=secgroup.id,
882 tenant_id=secgroup.tenant_id)
883 ruleset.update(kwargs)
884
David Kranz34e88122014-12-11 15:24:05 -0500885 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300886 sg_rule = net_resources.DeletableSecurityGroupRule(
887 client=client,
888 **sg_rule['security_group_rule']
889 )
890 self.addCleanup(self.delete_wrapper, sg_rule.delete)
891 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
892 self.assertEqual(secgroup.id, sg_rule.security_group_id)
893
894 return sg_rule
895
896 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
897 """These rules are intended to permit inbound ssh and icmp
898 traffic from all sources, so no group_id is provided.
899 Setting a group_id would only permit traffic from ports
900 belonging to the same security group.
901 """
902
903 if client is None:
904 client = self.network_client
905 rules = []
906 rulesets = [
907 dict(
908 # ssh
909 protocol='tcp',
910 port_range_min=22,
911 port_range_max=22,
912 ),
913 dict(
914 # ping
915 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +0100916 ),
917 dict(
918 # ipv6-icmp for ping6
919 protocol='icmp',
920 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +0300921 )
922 ]
923 for ruleset in rulesets:
924 for r_direction in ['ingress', 'egress']:
925 ruleset['direction'] = r_direction
926 try:
927 sg_rule = self._create_security_group_rule(
928 client=client, secgroup=secgroup, **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +0900929 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +0300930 # if rule already exist - skip rule and continue
931 msg = 'Security group rule already exists'
932 if msg not in ex._error_string:
933 raise ex
934 else:
935 self.assertEqual(r_direction, sg_rule.direction)
936 rules.append(sg_rule)
937
938 return rules
939
940 def _ssh_to_server(self, server, private_key):
941 ssh_login = CONF.compute.image_ssh_user
942 return self.get_remote_client(server,
943 username=ssh_login,
944 private_key=private_key)
945
Yair Frieddb6c9e92014-08-06 08:53:13 +0300946 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300947 """Retrieve a router for the given tenant id.
948
949 If a public router has been configured, it will be returned.
950
951 If a public router has not been configured, but a public
952 network has, a tenant router will be created and returned that
953 routes traffic to the public network.
954 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300955 if not client:
956 client = self.network_client
957 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000958 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300959 router_id = CONF.network.public_router_id
960 network_id = CONF.network.public_network_id
961 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -0400962 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +0400963 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300964 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300965 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300966 router.set_gateway(network_id)
967 return router
968 else:
969 raise Exception("Neither of 'public_router_id' or "
970 "'public_network_id' has been defined.")
971
Yair Frieddb6c9e92014-08-06 08:53:13 +0300972 def _create_router(self, client=None, tenant_id=None,
973 namestart='router-smoke'):
974 if not client:
975 client = self.network_client
976 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000977 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300978 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500979 result = client.create_router(name=name,
980 admin_state_up=True,
981 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300982 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300983 **result['router'])
984 self.assertEqual(router.name, name)
985 self.addCleanup(self.delete_wrapper, router.delete)
986 return router
987
Alok Maurya6384bbb2014-07-13 06:44:29 -0700988 def _update_router_admin_state(self, router, admin_state_up):
989 router.update(admin_state_up=admin_state_up)
990 self.assertEqual(admin_state_up, router.admin_state_up)
991
Yair Fried413bf2d2014-11-19 17:07:11 +0200992 def create_networks(self, client=None, tenant_id=None,
993 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300994 """Create a network with a subnet connected to a router.
995
David Shrewsbury9bac3662014-08-07 15:07:01 -0400996 The baremetal driver is a special case since all nodes are
997 on the same shared network.
998
Yair Fried413bf2d2014-11-19 17:07:11 +0200999 :param client: network client to create resources with.
1000 :param tenant_id: id of tenant to create resources in.
1001 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001002 :returns: network, subnet, router
1003 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001004 if CONF.baremetal.driver_enabled:
1005 # NOTE(Shrews): This exception is for environments where tenant
1006 # credential isolation is available, but network separation is
1007 # not (the current baremetal case). Likely can be removed when
1008 # test account mgmt is reworked:
1009 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001010 if not CONF.compute.fixed_network_name:
1011 m = 'fixed_network_name must be specified in config'
1012 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001013 network = self._get_network_by_name(
1014 CONF.compute.fixed_network_name)
1015 router = None
1016 subnet = None
1017 else:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001018 network = self._create_network(client=client, tenant_id=tenant_id)
1019 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001020
1021 subnet_kwargs = dict(network=network, client=client)
1022 # use explicit check because empty list is a valid option
1023 if dns_nameservers is not None:
1024 subnet_kwargs['dns_nameservers'] = dns_nameservers
1025 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001026 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001027 return network, subnet, router
1028
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001029 def create_server(self, name=None, image=None, flavor=None,
1030 wait_on_boot=True, wait_on_delete=True,
1031 create_kwargs=None):
1032 vnic_type = CONF.network.port_vnic_type
1033
1034 # If vnic_type is configured create port for
1035 # every network
1036 if vnic_type:
1037 ports = []
1038 networks = []
1039 create_port_body = {'binding:vnic_type': vnic_type,
1040 'namestart': 'port-smoke'}
1041 if create_kwargs:
1042 net_client = create_kwargs.get("network_client",
1043 self.network_client)
1044
1045 # Convert security group names to security group ids
1046 # to pass to create_port
1047 if create_kwargs.get('security_groups'):
1048 security_groups = net_client.list_security_groups().get(
1049 'security_groups')
1050 sec_dict = dict([(s['name'], s['id'])
1051 for s in security_groups])
1052
1053 sec_groups_names = [s['name'] for s in create_kwargs[
1054 'security_groups']]
1055 security_groups_ids = [sec_dict[s]
1056 for s in sec_groups_names]
1057
1058 if security_groups_ids:
1059 create_port_body[
1060 'security_groups'] = security_groups_ids
1061 networks = create_kwargs.get('networks')
1062 else:
1063 net_client = self.network_client
1064 # If there are no networks passed to us we look up
1065 # for the tenant's private networks and create a port
1066 # if there is only one private network. The same behaviour
1067 # as we would expect when passing the call to the clients
1068 # with no networks
1069 if not networks:
1070 networks = net_client.list_networks(filters={
1071 'router:external': False})
1072 self.assertEqual(1, len(networks),
1073 "There is more than one"
1074 " network for the tenant")
1075 for net in networks:
1076 net_id = net['uuid']
1077 port = self._create_port(network_id=net_id,
1078 client=net_client,
1079 **create_port_body)
1080 ports.append({'port': port.id})
1081 if ports:
1082 create_kwargs['networks'] = ports
1083
1084 return super(NetworkScenarioTest, self).create_server(
1085 name=name, image=image, flavor=flavor,
1086 wait_on_boot=wait_on_boot, wait_on_delete=wait_on_delete,
1087 create_kwargs=create_kwargs)
1088
Yair Fried1fc32a12014-08-04 09:11:30 +03001089
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001090# power/provision states as of icehouse
1091class BaremetalPowerStates(object):
1092 """Possible power states of an Ironic node."""
1093 POWER_ON = 'power on'
1094 POWER_OFF = 'power off'
1095 REBOOT = 'rebooting'
1096 SUSPEND = 'suspended'
1097
1098
1099class BaremetalProvisionStates(object):
1100 """Possible provision states of an Ironic node."""
1101 NOSTATE = None
1102 INIT = 'initializing'
1103 ACTIVE = 'active'
1104 BUILDING = 'building'
1105 DEPLOYWAIT = 'wait call-back'
1106 DEPLOYING = 'deploying'
1107 DEPLOYFAIL = 'deploy failed'
1108 DEPLOYDONE = 'deploy complete'
1109 DELETING = 'deleting'
1110 DELETED = 'deleted'
1111 ERROR = 'error'
1112
1113
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001114class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001115
1116 credentials = ['primary', 'admin']
1117
Adam Gandelman4a48a602014-03-20 18:23:18 -07001118 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001119 def skip_checks(cls):
1120 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001121 if (not CONF.service_available.ironic or
1122 not CONF.baremetal.driver_enabled):
1123 msg = 'Ironic not available or Ironic compute driver not enabled'
1124 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001125
1126 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001127 def setup_clients(cls):
1128 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001129
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001130 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001131
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001132 @classmethod
1133 def resource_setup(cls):
1134 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001135 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001136 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001137
1138 def _node_state_timeout(self, node_id, state_attr,
1139 target_states, timeout=10, interval=1):
1140 if not isinstance(target_states, list):
1141 target_states = [target_states]
1142
1143 def check_state():
1144 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001145 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001146 return True
1147 return False
1148
1149 if not tempest.test.call_until_true(
1150 check_state, timeout, interval):
1151 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1152 (node_id, state_attr, target_states))
1153 raise exceptions.TimeoutException(msg)
1154
1155 def wait_provisioning_state(self, node_id, state, timeout):
1156 self._node_state_timeout(
1157 node_id=node_id, state_attr='provision_state',
1158 target_states=state, timeout=timeout)
1159
1160 def wait_power_state(self, node_id, state):
1161 self._node_state_timeout(
1162 node_id=node_id, state_attr='power_state',
1163 target_states=state, timeout=CONF.baremetal.power_timeout)
1164
1165 def wait_node(self, instance_id):
1166 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001167
Adam Gandelman4a48a602014-03-20 18:23:18 -07001168 def _get_node():
1169 node = None
1170 try:
1171 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001172 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001173 pass
1174 return node is not None
1175
1176 if not tempest.test.call_until_true(
1177 _get_node, CONF.baremetal.association_timeout, 1):
1178 msg = ('Timed out waiting to get Ironic node by instance id %s'
1179 % instance_id)
1180 raise exceptions.TimeoutException(msg)
1181
1182 def get_node(self, node_id=None, instance_id=None):
1183 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001184 _, body = self.baremetal_client.show_node(node_id)
1185 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001186 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001187 _, body = self.baremetal_client.show_node_by_instance_uuid(
1188 instance_id)
1189 if body['nodes']:
1190 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001191
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001192 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001193 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001194 _, body = self.baremetal_client.list_node_ports(node_uuid)
1195 for port in body['ports']:
1196 _, p = self.baremetal_client.show_port(port['uuid'])
1197 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001198 return ports
1199
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001200 def add_keypair(self):
1201 self.keypair = self.create_keypair()
1202
1203 def verify_connectivity(self, ip=None):
1204 if ip:
1205 dest = self.get_remote_client(ip)
1206 else:
1207 dest = self.get_remote_client(self.instance)
1208 dest.validate_authentication()
1209
1210 def boot_instance(self):
1211 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001212 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001213 }
1214 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001215 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001216
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001217 self.wait_node(self.instance['id'])
1218 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001219
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001220 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001221
1222 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001223 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001224 [BaremetalProvisionStates.DEPLOYWAIT,
1225 BaremetalProvisionStates.ACTIVE],
1226 timeout=15)
1227
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001228 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001229 BaremetalProvisionStates.ACTIVE,
1230 timeout=CONF.baremetal.active_timeout)
1231
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001232 waiters.wait_for_server_status(self.servers_client,
1233 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001234 self.node = self.get_node(instance_id=self.instance['id'])
Ken'ichi Ohmichi76800242015-07-03 05:12:31 +00001235 self.instance = self.servers_client.show_server(self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001236
1237 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001238 self.servers_client.delete_server(self.instance['id'])
1239 self.wait_power_state(self.node['uuid'],
1240 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001241 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001242 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001243 BaremetalProvisionStates.NOSTATE,
1244 timeout=CONF.baremetal.unprovision_timeout)
1245
Adam Gandelman4a48a602014-03-20 18:23:18 -07001246
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001247class EncryptionScenarioTest(ScenarioTest):
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001248 """
1249 Base class for encryption scenario tests
1250 """
1251
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001252 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001253
1254 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001255 def setup_clients(cls):
1256 super(EncryptionScenarioTest, cls).setup_clients()
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001257 cls.admin_volume_types_client = cls.os_adm.volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001258
1259 def _wait_for_volume_status(self, status):
1260 self.status_timeout(
1261 self.volume_client.volumes, self.volume.id, status)
1262
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001263 def nova_boot(self):
1264 self.keypair = self.create_keypair()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001265 create_kwargs = {'key_name': self.keypair['name']}
1266 self.server = self.create_server(image=self.image,
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001267 create_kwargs=create_kwargs)
1268
1269 def create_volume_type(self, client=None, name=None):
1270 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001271 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001272 if not name:
1273 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001274 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001275 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001276 body = client.create_volume_type(
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001277 randomized_name)
1278 self.assertIn('id', body)
1279 self.addCleanup(client.delete_volume_type, body['id'])
1280 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001281
1282 def create_encryption_type(self, client=None, type_id=None, provider=None,
1283 key_size=None, cipher=None,
1284 control_location=None):
1285 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001286 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001287 if not type_id:
1288 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001289 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001290 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001291 client.create_encryption_type(
1292 type_id, provider=provider, key_size=key_size, cipher=cipher,
1293 control_location=control_location)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001294
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001295
Chris Dent0d494112014-08-26 13:48:30 +01001296class SwiftScenarioTest(ScenarioTest):
1297 """
1298 Provide harness to do Swift scenario tests.
1299
1300 Subclasses implement the tests that use the methods provided by this
1301 class.
1302 """
1303
1304 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001305 def skip_checks(cls):
1306 super(SwiftScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001307 if not CONF.service_available.swift:
1308 skip_msg = ("%s skipped as swift is not available" %
1309 cls.__name__)
1310 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001311
1312 @classmethod
1313 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001314 cls.set_network_resources()
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001315 super(SwiftScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001316 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001317 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001318
1319 @classmethod
1320 def setup_clients(cls):
1321 super(SwiftScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001322 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001323 cls.account_client = cls.os_operator.account_client
1324 cls.container_client = cls.os_operator.container_client
1325 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001326
Chris Dentde456a12014-09-10 12:41:15 +01001327 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001328 """get swift status for our user account."""
1329 self.account_client.list_account_containers()
1330 LOG.debug('Swift status information obtained successfully')
1331
Chris Dentde456a12014-09-10 12:41:15 +01001332 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001333 name = container_name or data_utils.rand_name(
1334 'swift-scenario-container')
1335 self.container_client.create_container(name)
1336 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001337 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001338 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001339 self.addCleanup(self.delete_wrapper,
1340 self.container_client.delete_container,
1341 name)
Chris Dent0d494112014-08-26 13:48:30 +01001342 return name
1343
Chris Dentde456a12014-09-10 12:41:15 +01001344 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001345 self.container_client.delete_container(container_name)
1346 LOG.debug('Container %s deleted' % (container_name))
1347
Chris Dentde456a12014-09-10 12:41:15 +01001348 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001349 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1350 obj_data = data_utils.arbitrary_string()
1351 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001352 self.addCleanup(self.delete_wrapper,
1353 self.object_client.delete_object,
1354 container_name,
1355 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001356 return obj_name, obj_data
1357
Chris Dentde456a12014-09-10 12:41:15 +01001358 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001359 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001360 self.list_and_check_container_objects(container_name,
1361 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001362
Chris Dentde456a12014-09-10 12:41:15 +01001363 def list_and_check_container_objects(self, container_name,
1364 present_obj=None,
1365 not_present_obj=None):
Chris Dent0d494112014-08-26 13:48:30 +01001366 """
1367 List objects for a given container and assert which are present and
1368 which are not.
1369 """
Ghanshyam2a180b82014-06-16 13:54:22 +09001370 if present_obj is None:
1371 present_obj = []
1372 if not_present_obj is None:
1373 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001374 _, object_list = self.container_client.list_container_contents(
1375 container_name)
1376 if present_obj:
1377 for obj in present_obj:
1378 self.assertIn(obj, object_list)
1379 if not_present_obj:
1380 for obj in not_present_obj:
1381 self.assertNotIn(obj, object_list)
1382
Chris Dentde456a12014-09-10 12:41:15 +01001383 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001384 metadata_param = {'metadata_prefix': 'x-container-',
1385 'metadata': {'read': acl}}
1386 self.container_client.update_container_metadata(container_name,
1387 **metadata_param)
1388 resp, _ = self.container_client.list_container_metadata(container_name)
1389 self.assertEqual(resp['x-container-read'], acl)
1390
Chris Dentde456a12014-09-10 12:41:15 +01001391 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001392 _, obj = self.object_client.get_object(container_name, obj_name)
1393 self.assertEqual(obj, expected_data)