blob: 67e2f8653569a408b2c9ef820a27b94b4e054279 [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
Sean Dague6dbc6da2013-05-08 17:49:46 -04002# Copyright 2013 IBM Corp.
3# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16
Sean Dague6dbc6da2013-05-08 17:49:46 -040017import subprocess
18
Sean Dague6dbc6da2013-05-08 17:49:46 -040019import netaddr
Doug Hellmann583ce2c2015-03-11 14:55:46 +000020from oslo_log import log
Matthew Treinish96e9e882014-06-09 18:37:19 -040021import six
Matt Riedemann5f0ac522015-05-21 09:16:24 -070022from tempest_lib.common.utils import misc as misc_utils
Masayuki Igawad9388762015-01-20 14:56:42 +090023from tempest_lib import exceptions as lib_exc
Sean Dague6dbc6da2013-05-08 17:49:46 -040024
Rohan Kanade9ce97df2013-12-10 18:59:35 +053025from tempest.common import fixed_network
Fei Long Wangd39431f2015-05-14 11:30:48 +120026from tempest.common.utils import data_utils
Masayuki Igawa4ded9f02014-02-17 15:05:59 +090027from tempest.common.utils.linux import remote_client
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +000028from tempest.common import waiters
Matthew Treinish6c072292014-01-29 19:15:52 +000029from tempest import config
Giulio Fidente92f77192013-08-26 17:13:28 +020030from tempest import exceptions
Yair Fried1fc32a12014-08-04 09:11:30 +030031from tempest.services.network import resources as net_resources
Sean Dague6dbc6da2013-05-08 17:49:46 -040032import tempest.test
Sean Dague6dbc6da2013-05-08 17:49:46 -040033
Matthew Treinish6c072292014-01-29 19:15:52 +000034CONF = config.CONF
Sean Dague6dbc6da2013-05-08 17:49:46 -040035
Attila Fazekasfb7552a2013-08-27 13:02:26 +020036LOG = log.getLogger(__name__)
37
Sean Dague6dbc6da2013-05-08 17:49:46 -040038
Andrea Frittoli2e733b52014-07-16 14:12:11 +010039class ScenarioTest(tempest.test.BaseTestCase):
Andrea Frittoli486ede72014-09-25 11:50:05 +010040 """Base class for scenario tests. Uses tempest own clients. """
Andrea Frittoli2e733b52014-07-16 14:12:11 +010041
Andrea Frittolib21de6c2015-02-06 20:12:38 +000042 credentials = ['primary']
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000043
44 @classmethod
45 def setup_clients(cls):
46 super(ScenarioTest, cls).setup_clients()
Andrea Frittoli247058f2014-07-16 16:09:22 +010047 # Clients (in alphabetical order)
Adam Gandelmanc78c7572014-08-28 18:38:55 -070048 cls.flavors_client = cls.manager.flavors_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010049 cls.floating_ips_client = cls.manager.floating_ips_client
50 # Glance image client v1
51 cls.image_client = cls.manager.image_client
nithya-ganesan882595e2014-07-29 18:51:07 +000052 # Compute image client
53 cls.images_client = cls.manager.images_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010054 cls.keypairs_client = cls.manager.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010055 # Nova security groups client
56 cls.security_groups_client = cls.manager.security_groups_client
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +000057 cls.security_group_rules_client = (
58 cls.manager.security_group_rules_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +010059 cls.servers_client = cls.manager.servers_client
60 cls.volumes_client = cls.manager.volumes_client
Joseph Lanouxeef192f2014-08-01 14:32:53 +000061 cls.snapshots_client = cls.manager.snapshots_client
Yair Fried1fc32a12014-08-04 09:11:30 +030062 cls.interface_client = cls.manager.interfaces_client
63 # Neutron network client
64 cls.network_client = cls.manager.network_client
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090065 # Heat client
66 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010067
Andrea Frittoli247058f2014-07-16 16:09:22 +010068 # ## Methods to handle sync and async deletes
69
70 def setUp(self):
71 super(ScenarioTest, self).setUp()
72 self.cleanup_waits = []
73 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
74 # because scenario tests in the same test class should not share
75 # resources. If resources were shared between test cases then it
76 # should be a single scenario test instead of multiples.
77
78 # NOTE(yfried): this list is cleaned at the end of test_methods and
79 # not at the end of the class
80 self.addCleanup(self._wait_for_cleanups)
81
Yair Fried1fc32a12014-08-04 09:11:30 +030082 def delete_wrapper(self, delete_thing, *args, **kwargs):
Andrea Frittoli247058f2014-07-16 16:09:22 +010083 """Ignores NotFound exceptions for delete operations.
84
Yair Fried1fc32a12014-08-04 09:11:30 +030085 @param delete_thing: delete method of a resource. method will be
86 executed as delete_thing(*args, **kwargs)
87
Andrea Frittoli247058f2014-07-16 16:09:22 +010088 """
89 try:
90 # Tempest clients return dicts, so there is no common delete
91 # method available. Using a callable instead
Yair Fried1fc32a12014-08-04 09:11:30 +030092 delete_thing(*args, **kwargs)
Masayuki Igawabfa07602015-01-20 18:47:17 +090093 except lib_exc.NotFound:
Andrea Frittoli247058f2014-07-16 16:09:22 +010094 # If the resource is already missing, mission accomplished.
95 pass
96
97 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +090098 cleanup_callable, cleanup_args=None,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +000099 cleanup_kwargs=None, waiter_client=None):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700100 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100101
102 @param waiter_callable: callable to wait for the resource to delete
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000103 with the following waiter_client if specified.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100104 @param thing_id: the id of the resource to be cleaned-up
105 @param thing_id_param: the name of the id param in the waiter
106 @param cleanup_callable: method to load pass to self.addCleanup with
107 the following *cleanup_args, **cleanup_kwargs.
108 usually a delete method.
109 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900110 if cleanup_args is None:
111 cleanup_args = []
112 if cleanup_kwargs is None:
113 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100114 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
115 wait_dict = {
116 'waiter_callable': waiter_callable,
117 thing_id_param: thing_id
118 }
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000119 if waiter_client:
120 wait_dict['client'] = waiter_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100121 self.cleanup_waits.append(wait_dict)
122
123 def _wait_for_cleanups(self):
124 """To handle async delete actions, a list of waits is added
125 which will be iterated over as the last step of clearing the
126 cleanup queue. That way all the delete calls are made up front
127 and the tests won't succeed unless the deletes are eventually
128 successful. This is the same basic approach used in the api tests to
129 limit cleanup execution time except here it is multi-resource,
130 because of the nature of the scenario tests.
131 """
132 for wait in self.cleanup_waits:
133 waiter_callable = wait.pop('waiter_callable')
134 waiter_callable(**wait)
135
136 # ## Test functions library
137 #
138 # The create_[resource] functions only return body and discard the
139 # resp part which is not used in scenario tests
140
Yair Frieddb6c9e92014-08-06 08:53:13 +0300141 def create_keypair(self, client=None):
142 if not client:
143 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100144 name = data_utils.rand_name(self.__class__.__name__)
145 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000146 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300147 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900148 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100149
150 def create_server(self, name=None, image=None, flavor=None,
151 wait_on_boot=True, wait_on_delete=True,
Ghanshyam2a180b82014-06-16 13:54:22 +0900152 create_kwargs=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100153 """Creates VM instance.
154
155 @param image: image from which to create the instance
156 @param wait_on_boot: wait for status ACTIVE before continue
157 @param wait_on_delete: force synchronous delete on cleanup
158 @param create_kwargs: additional details for instance creation
159 @return: server dict
160 """
161 if name is None:
162 name = data_utils.rand_name(self.__class__.__name__)
163 if image is None:
164 image = CONF.compute.image_ref
165 if flavor is None:
166 flavor = CONF.compute.flavor_ref
Ghanshyam2a180b82014-06-16 13:54:22 +0900167 if create_kwargs is None:
168 create_kwargs = {}
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530169 network = self.get_tenant_network()
Matthew Treinish4bbc1992015-04-07 11:13:40 -0400170 create_kwargs = fixed_network.set_networks_kwarg(network,
171 create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100172
Andrea Frittoli247058f2014-07-16 16:09:22 +0100173 LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
174 name, image, flavor)
David Kranz0fb14292015-02-11 15:55:20 -0500175 server = self.servers_client.create_server(name, image, flavor,
176 **create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100177 if wait_on_delete:
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000178 self.addCleanup(waiters.wait_for_server_termination,
179 self.servers_client,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100180 server['id'])
181 self.addCleanup_with_wait(
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000182 waiter_callable=waiters.wait_for_server_termination,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100183 thing_id=server['id'], thing_id_param='server_id',
184 cleanup_callable=self.delete_wrapper,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000185 cleanup_args=[self.servers_client.delete_server, server['id']],
186 waiter_client=self.servers_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100187 if wait_on_boot:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000188 waiters.wait_for_server_status(self.servers_client,
189 server_id=server['id'],
190 status='ACTIVE')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100191 # The instance retrieved on creation is missing network
192 # details, necessitating retrieval after it becomes active to
193 # ensure correct details.
Ken'ichi Ohmichi76800242015-07-03 05:12:31 +0000194 server = self.servers_client.show_server(server['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100195 self.assertEqual(server['name'], name)
196 return server
197
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100198 def create_volume(self, size=None, name=None, snapshot_id=None,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100199 imageRef=None, volume_type=None, wait_on_delete=True):
200 if name is None:
201 name = data_utils.rand_name(self.__class__.__name__)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000202 volume = self.volumes_client.create_volume(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100203 size=size, display_name=name, snapshot_id=snapshot_id,
204 imageRef=imageRef, volume_type=volume_type)
Matt Riedemanne85c2702014-09-10 11:50:13 -0700205
Andrea Frittoli247058f2014-07-16 16:09:22 +0100206 if wait_on_delete:
207 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
208 volume['id'])
Matt Riedemanne85c2702014-09-10 11:50:13 -0700209 self.addCleanup(self.delete_wrapper,
210 self.volumes_client.delete_volume, volume['id'])
211 else:
212 self.addCleanup_with_wait(
213 waiter_callable=self.volumes_client.wait_for_resource_deletion,
214 thing_id=volume['id'], thing_id_param='id',
215 cleanup_callable=self.delete_wrapper,
216 cleanup_args=[self.volumes_client.delete_volume, volume['id']])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100217
218 self.assertEqual(name, volume['display_name'])
219 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
220 # The volume retrieved on creation has a non-up-to-date status.
221 # Retrieval after it becomes active ensures correct details.
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000222 volume = self.volumes_client.show_volume(volume['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100223 return volume
224
Yair Fried1fc32a12014-08-04 09:11:30 +0300225 def _create_loginable_secgroup_rule(self, secgroup_id=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100226 _client = self.security_groups_client
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000227 _client_rules = self.security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100228 if secgroup_id is None:
David Kranz9964b4e2015-02-06 15:45:29 -0500229 sgs = _client.list_security_groups()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100230 for sg in sgs:
231 if sg['name'] == 'default':
232 secgroup_id = sg['id']
233
234 # These rules are intended to permit inbound ssh and icmp
235 # traffic from all sources, so no group_id is provided.
236 # Setting a group_id would only permit traffic from ports
237 # belonging to the same security group.
238 rulesets = [
239 {
240 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000241 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100242 'from_port': 22,
243 'to_port': 22,
244 'cidr': '0.0.0.0/0',
245 },
246 {
247 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000248 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100249 'from_port': -1,
250 'to_port': -1,
251 'cidr': '0.0.0.0/0',
252 }
253 ]
254 rules = list()
255 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000256 sg_rule = _client_rules.create_security_group_rule(
257 parent_group_id=secgroup_id, **ruleset)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100258 self.addCleanup(self.delete_wrapper,
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000259 _client_rules.delete_security_group_rule,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100260 sg_rule['id'])
261 rules.append(sg_rule)
262 return rules
263
Yair Fried1fc32a12014-08-04 09:11:30 +0300264 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100265 # Create security group
266 sg_name = data_utils.rand_name(self.__class__.__name__)
267 sg_desc = sg_name + " description"
David Kranz9964b4e2015-02-06 15:45:29 -0500268 secgroup = self.security_groups_client.create_security_group(
Ken'ichi Ohmichi34563cc2015-07-21 00:53:17 +0000269 name=sg_name, description=sg_desc)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100270 self.assertEqual(secgroup['name'], sg_name)
271 self.assertEqual(secgroup['description'], sg_desc)
272 self.addCleanup(self.delete_wrapper,
273 self.security_groups_client.delete_security_group,
274 secgroup['id'])
275
276 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300277 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100278
279 return secgroup
280
JordanP3fe2dc32014-11-17 13:06:01 +0100281 def get_remote_client(self, server_or_ip, username=None, private_key=None,
282 log_console_of_servers=None):
283 """Get a SSH client to a remote server
284
285 @param server_or_ip a server object as returned by Tempest compute
286 client or an IP address to connect to
287 @param username name of the Linux account on the remote server
288 @param private_key the SSH private key to use
289 @param log_console_of_servers a list of server objects. Each server
290 in the list will have its console printed in the logs in case the
291 SSH connection failed to be established
292 @return a RemoteClient object
293 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100294 if isinstance(server_or_ip, six.string_types):
295 ip = server_or_ip
296 else:
Andrew Boik4a3daf12015-03-27 01:59:31 -0400297 addrs = server_or_ip['addresses'][CONF.compute.network_for_ssh]
298 try:
299 ip = (addr['addr'] for addr in addrs if
300 netaddr.valid_ipv4(addr['addr'])).next()
301 except StopIteration:
302 raise lib_exc.NotFound("No IPv4 addresses to use for SSH to "
303 "remote server.")
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700304
Andrea Frittoli247058f2014-07-16 16:09:22 +0100305 if username is None:
306 username = CONF.scenario.ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800307 # Set this with 'keypair' or others to log in with keypair or
308 # username/password.
309 if CONF.compute.ssh_auth_method == 'keypair':
310 password = None
311 if private_key is None:
312 private_key = self.keypair['private_key']
313 else:
314 password = CONF.compute.image_ssh_password
315 private_key = None
Andrea Frittoli247058f2014-07-16 16:09:22 +0100316 linux_client = remote_client.RemoteClient(ip, username,
wantwatering896300c2015-03-27 15:17:42 +0800317 pkey=private_key,
318 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100319 try:
320 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700321 except Exception as e:
322 message = ('Initializing SSH connection to %(ip)s failed. '
323 'Error: %(error)s' % {'ip': ip, 'error': e})
324 caller = misc_utils.find_test_caller()
325 if caller:
326 message = '(%s) %s' % (caller, message)
327 LOG.exception(message)
Marc Kodererb06db502015-04-30 09:31:27 +0200328 # If we don't explicitly set for which servers we want to
JordanP3fe2dc32014-11-17 13:06:01 +0100329 # log the console output then all the servers will be logged.
330 # See the definition of _log_console_output()
331 self._log_console_output(log_console_of_servers)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100332 raise
333
334 return linux_client
335
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000336 def _image_create(self, name, fmt, path,
337 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900338 if properties is None:
339 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100340 name = data_utils.rand_name('%s-' % name)
341 image_file = open(path, 'rb')
342 self.addCleanup(image_file.close)
343 params = {
344 'name': name,
345 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000346 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100347 'is_public': 'False',
348 }
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000349 params['properties'] = properties
John Warren66207252015-07-31 15:51:02 -0400350 image = self.image_client.create_image(**params)['image']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100351 self.addCleanup(self.image_client.delete_image, image['id'])
352 self.assertEqual("queued", image['status'])
353 self.image_client.update_image(image['id'], data=image_file)
354 return image['id']
355
356 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300357 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100358 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
359 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
360 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300361 img_container_format = CONF.scenario.img_container_format
362 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000363 img_properties = CONF.scenario.img_properties
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300364 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000365 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300366 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000367 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100368 try:
369 self.image = self._image_create('scenario-img',
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300370 img_container_format,
371 img_path,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000372 disk_format=img_disk_format,
373 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100374 except IOError:
375 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
376 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
377 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000378 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100379 self.image = self._image_create('scenario-ami', 'ami',
380 path=ami_img_path,
381 properties=properties)
382 LOG.debug("image:%s" % self.image)
383
384 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400385 if not CONF.compute_feature_enabled.console_output:
386 LOG.debug('Console output not supported, cannot log')
387 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100388 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500389 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100390 servers = servers['servers']
391 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500392 console_output = self.servers_client.get_console_output(
David Kranzae99b9a2015-02-16 13:37:01 -0500393 server['id'], length=None).data
394 LOG.debug('Console output for %s\nbody=\n%s',
395 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100396
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000397 def _log_net_info(self, exc):
398 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300399 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000400 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000401
nithya-ganesan882595e2014-07-29 18:51:07 +0000402 def create_server_snapshot(self, server, name=None):
403 # Glance client
404 _image_client = self.image_client
405 # Compute client
406 _images_client = self.images_client
407 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000408 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000409 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000410 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500411 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000412 _image_client.wait_for_image_status(image_id, 'active')
413 self.addCleanup_with_wait(
414 waiter_callable=_image_client.wait_for_resource_deletion,
415 thing_id=image_id, thing_id_param='id',
416 cleanup_callable=self.delete_wrapper,
417 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500418 snapshot_image = _image_client.get_image_meta(image_id)
nithya-ganesan882595e2014-07-29 18:51:07 +0000419 image_name = snapshot_image['name']
420 self.assertEqual(name, image_name)
421 LOG.debug("Created snapshot image %s for server %s",
422 image_name, server['name'])
423 return snapshot_image
424
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900425 def nova_volume_attach(self):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000426 volume = self.servers_client.attach_volume(
Ken'ichi Ohmichidfc88de2015-08-13 05:12:20 +0000427 self.server['id'], volumeId=self.volume['id'], device='/dev/%s'
Alexander Gubanove0634ab2015-05-25 10:28:25 +0300428 % CONF.compute.volume_device_name)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900429 self.assertEqual(self.volume['id'], volume['id'])
430 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
431 # Refresh the volume after the attachment
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000432 self.volume = self.volumes_client.show_volume(volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900433
434 def nova_volume_detach(self):
435 self.servers_client.detach_volume(self.server['id'], self.volume['id'])
436 self.volumes_client.wait_for_volume_status(self.volume['id'],
437 'available')
438
Ken'ichi Ohmichi35798fb2015-04-06 01:22:41 +0000439 volume = self.volumes_client.show_volume(self.volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900440 self.assertEqual('available', volume['status'])
441
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700442 def rebuild_server(self, server_id, image=None,
443 preserve_ephemeral=False, wait=True,
444 rebuild_kwargs=None):
445 if image is None:
446 image = CONF.compute.image_ref
447
448 rebuild_kwargs = rebuild_kwargs or {}
449
450 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
451 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000452 self.servers_client.rebuild_server(
453 server_id=server_id, image_ref=image,
454 preserve_ephemeral=preserve_ephemeral,
455 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700456 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000457 waiters.wait_for_server_status(self.servers_client,
458 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700459
Steven Hardyda2a8352014-10-02 12:52:20 +0100460 def ping_ip_address(self, ip_address, should_succeed=True,
461 ping_timeout=None):
462 timeout = ping_timeout or CONF.compute.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700463 cmd = ['ping', '-c1', '-w1', ip_address]
464
465 def ping():
466 proc = subprocess.Popen(cmd,
467 stdout=subprocess.PIPE,
468 stderr=subprocess.PIPE)
469 proc.communicate()
470 return (proc.returncode == 0) == should_succeed
471
Steven Hardyda2a8352014-10-02 12:52:20 +0100472 return tempest.test.call_until_true(ping, timeout, 1)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700473
Yair Friedae0e73d2014-11-24 11:56:26 +0200474 def check_vm_connectivity(self, ip_address,
475 username=None,
476 private_key=None,
477 should_connect=True):
478 """
479 :param ip_address: server to test against
480 :param username: server's ssh username
481 :param private_key: server's ssh private key to be used
482 :param should_connect: True/False indicates positive/negative test
483 positive - attempt ping and ssh
484 negative - attempt ping and fail if succeed
485
486 :raises: AssertError if the result of the connectivity check does
487 not match the value of the should_connect param
488 """
489 if should_connect:
490 msg = "Timed out waiting for %s to become reachable" % ip_address
491 else:
492 msg = "ip address %s is reachable" % ip_address
493 self.assertTrue(self.ping_ip_address(ip_address,
494 should_succeed=should_connect),
495 msg=msg)
496 if should_connect:
497 # no need to check ssh for negative connectivity
498 self.get_remote_client(ip_address, username, private_key)
499
500 def check_public_network_connectivity(self, ip_address, username,
501 private_key, should_connect=True,
502 msg=None, servers=None):
503 # The target login is assumed to have been configured for
504 # key-based authentication by cloud-init.
505 LOG.debug('checking network connections to IP %s with user: %s' %
506 (ip_address, username))
507 try:
508 self.check_vm_connectivity(ip_address,
509 username,
510 private_key,
511 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500512 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200513 ex_msg = 'Public network connectivity check failed'
514 if msg:
515 ex_msg += ": " + msg
516 LOG.exception(ex_msg)
517 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200518 raise
519
520 def create_floating_ip(self, thing, pool_name=None):
521 """Creates a floating IP and associates to a server using
522 Nova clients
523 """
524
ghanshyam9a3a9a22015-08-18 17:03:55 +0900525 floating_ip = (self.floating_ips_client.create_floating_ip(pool_name)
526 ['floating_ip'])
Yair Friedae0e73d2014-11-24 11:56:26 +0200527 self.addCleanup(self.delete_wrapper,
528 self.floating_ips_client.delete_floating_ip,
529 floating_ip['id'])
530 self.floating_ips_client.associate_floating_ip_to_server(
531 floating_ip['ip'], thing['id'])
532 return floating_ip
533
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100534
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100535class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300536 """Base class for network scenario tests.
537 This class provide helpers for network scenario tests, using the neutron
538 API. Helpers from ancestor which use the nova network API are overridden
539 with the neutron API.
540
541 This Class also enforces using Neutron instead of novanetwork.
542 Subclassed tests will be skipped if Neutron is not enabled
543
544 """
545
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000546 credentials = ['primary', 'admin']
547
Yair Fried1fc32a12014-08-04 09:11:30 +0300548 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000549 def skip_checks(cls):
550 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100551 if not CONF.service_available.neutron:
552 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300553
554 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100555 def resource_setup(cls):
556 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300557 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300558
Yair Frieddb6c9e92014-08-06 08:53:13 +0300559 def _create_network(self, client=None, tenant_id=None,
560 namestart='network-smoke-'):
561 if not client:
562 client = self.network_client
563 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000564 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300565 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500566 result = client.create_network(name=name, tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300567 network = net_resources.DeletableNetwork(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300568 **result['network'])
569 self.assertEqual(network.name, name)
570 self.addCleanup(self.delete_wrapper, network.delete)
571 return network
572
573 def _list_networks(self, *args, **kwargs):
574 """List networks using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900575 networks_list = self.admin_manager.network_client.list_networks(
576 *args, **kwargs)
577 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300578
579 def _list_subnets(self, *args, **kwargs):
580 """List subnets using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900581 subnets_list = self.admin_manager.network_client.list_subnets(
582 *args, **kwargs)
583 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300584
585 def _list_routers(self, *args, **kwargs):
586 """List routers using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900587 routers_list = self.admin_manager.network_client.list_routers(
588 *args, **kwargs)
589 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300590
591 def _list_ports(self, *args, **kwargs):
592 """List ports using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900593 ports_list = self.admin_manager.network_client.list_ports(
594 *args, **kwargs)
595 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300596
Yair Frieddb6c9e92014-08-06 08:53:13 +0300597 def _create_subnet(self, network, client=None, namestart='subnet-smoke',
598 **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300599 """
600 Create a subnet for the given network within the cidr block
601 configured for tenant networks.
602 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300603 if not client:
604 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300605
606 def cidr_in_use(cidr, tenant_id):
607 """
608 :return True if subnet with cidr already exist in tenant
609 False else
610 """
611 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
612 return len(cidr_in_use) != 0
613
Kirill Shileev14113572014-11-21 16:58:02 +0300614 ip_version = kwargs.pop('ip_version', 4)
615
616 if ip_version == 6:
617 tenant_cidr = netaddr.IPNetwork(
618 CONF.network.tenant_network_v6_cidr)
619 num_bits = CONF.network.tenant_network_v6_mask_bits
620 else:
621 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
622 num_bits = CONF.network.tenant_network_mask_bits
623
Yair Fried1fc32a12014-08-04 09:11:30 +0300624 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300625 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300626 # Repeatedly attempt subnet creation with sequential cidr
627 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300628 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300629 str_cidr = str(subnet_cidr)
630 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
631 continue
632
633 subnet = dict(
634 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300635 network_id=network.id,
636 tenant_id=network.tenant_id,
637 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300638 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300639 **kwargs
640 )
641 try:
David Kranz34e88122014-12-11 15:24:05 -0500642 result = client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300643 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900644 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300645 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
646 if not is_overlapping_cidr:
647 raise
648 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300649 subnet = net_resources.DeletableSubnet(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300650 **result['subnet'])
651 self.assertEqual(subnet.cidr, str_cidr)
652 self.addCleanup(self.delete_wrapper, subnet.delete)
653 return subnet
654
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200655 def _create_port(self, network_id, client=None, namestart='port-quotatest',
656 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300657 if not client:
658 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300659 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500660 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300661 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200662 network_id=network_id,
663 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300664 self.assertIsNotNone(result, 'Unable to allocate port')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300665 port = net_resources.DeletablePort(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300666 **result['port'])
667 self.addCleanup(self.delete_wrapper, port.delete)
668 return port
669
Kirill Shileev14113572014-11-21 16:58:02 +0300670 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300671 ports = self._list_ports(device_id=server['id'],
672 fixed_ip=ip_addr)
Kirill Shileev14113572014-11-21 16:58:02 +0300673 # it might happen here that this port has more then one ip address
674 # as in case of dual stack- when this port is created on 2 subnets
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200675 port_map = [(p["id"], fxip["ip_address"])
676 for p in ports
677 for fxip in p["fixed_ips"]
678 if netaddr.valid_ipv4(fxip["ip_address"])]
679
680 self.assertEqual(len(port_map), 1,
681 "Found multiple IPv4 addresses: %s. "
682 "Unable to determine which port to target."
683 % port_map)
684 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300685
David Shrewsbury9bac3662014-08-07 15:07:01 -0400686 def _get_network_by_name(self, network_name):
687 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700688 self.assertNotEqual(len(net), 0,
689 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300690 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400691
Yair Friedae0e73d2014-11-24 11:56:26 +0200692 def create_floating_ip(self, thing, external_network_id=None,
693 port_id=None, client=None):
694 """Creates a floating IP and associates to a resource/port using
695 Neutron client
696 """
697 if not external_network_id:
698 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300699 if not client:
700 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300701 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300702 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
703 else:
704 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500705 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300706 floating_network_id=external_network_id,
707 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300708 tenant_id=thing['tenant_id'],
709 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300710 )
711 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300712 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300713 **result['floatingip'])
714 self.addCleanup(self.delete_wrapper, floating_ip.delete)
715 return floating_ip
716
717 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300718 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300719 floating_ip.update(port_id=port_id)
720 self.assertEqual(port_id, floating_ip.port_id)
721 return floating_ip
722
723 def _disassociate_floating_ip(self, floating_ip):
724 """
725 :param floating_ip: type DeletableFloatingIp
726 """
727 floating_ip.update(port_id=None)
728 self.assertIsNone(floating_ip.port_id)
729 return floating_ip
730
Yair Fried45f92952014-06-26 05:19:19 +0300731 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000732 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300733
734 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
735 to check status
736 :param status: target status
737 :raises: AssertionError if status doesn't match
738 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000739 def refresh():
740 floating_ip.refresh()
741 return status == floating_ip.status
742
743 tempest.test.call_until_true(refresh,
744 CONF.network.build_timeout,
745 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300746 self.assertEqual(status, floating_ip.status,
747 message="FloatingIP: {fp} is at status: {cst}. "
748 "failed to reach status: {st}"
749 .format(fp=floating_ip, cst=floating_ip.status,
750 st=status))
751 LOG.info("FloatingIP: {fp} is at status: {st}"
752 .format(fp=floating_ip, st=status))
753
Yair Fried1fc32a12014-08-04 09:11:30 +0300754 def _check_tenant_network_connectivity(self, server,
755 username,
756 private_key,
757 should_connect=True,
758 servers_for_debug=None):
759 if not CONF.network.tenant_networks_reachable:
760 msg = 'Tenant networks not configured to be reachable.'
761 LOG.info(msg)
762 return
763 # The target login is assumed to have been configured for
764 # key-based authentication by cloud-init.
765 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400766 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300767 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900768 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200769 username,
770 private_key,
771 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300772 except Exception as e:
773 LOG.exception('Tenant network connectivity check failed')
774 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000775 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300776 raise
777
778 def _check_remote_connectivity(self, source, dest, should_succeed=True):
779 """
780 check ping server via source ssh connection
781
782 :param source: RemoteClient: an ssh connection from which to ping
783 :param dest: and IP to ping against
784 :param should_succeed: boolean should ping succeed or not
785 :returns: boolean -- should_succeed == ping
786 :returns: ping is false if ping failed
787 """
788 def ping_remote():
789 try:
790 source.ping_host(dest)
Andrey Pavlov64723762015-04-29 06:24:58 +0300791 except lib_exc.SSHExecCommandFailed:
Yair Fried1fc32a12014-08-04 09:11:30 +0300792 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
793 % (dest, source.ssh_client.host))
794 return not should_succeed
795 return should_succeed
796
797 return tempest.test.call_until_true(ping_remote,
798 CONF.compute.ping_timeout,
799 1)
800
Yair Frieddb6c9e92014-08-06 08:53:13 +0300801 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300802 namestart='secgroup-smoke'):
803 if client is None:
804 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300805 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000806 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300807 secgroup = self._create_empty_security_group(namestart=namestart,
808 client=client,
809 tenant_id=tenant_id)
810
811 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900812 rules = self._create_loginable_secgroup_rule(client=client,
813 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300814 for rule in rules:
815 self.assertEqual(tenant_id, rule.tenant_id)
816 self.assertEqual(secgroup.id, rule.security_group_id)
817 return secgroup
818
Yair Frieddb6c9e92014-08-06 08:53:13 +0300819 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300820 namestart='secgroup-smoke'):
821 """Create a security group without rules.
822
823 Default rules will be created:
824 - IPv4 egress to any
825 - IPv6 egress to any
826
827 :param tenant_id: secgroup will be created in this tenant
828 :returns: DeletableSecurityGroup -- containing the secgroup created
829 """
830 if client is None:
831 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300832 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000833 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300834 sg_name = data_utils.rand_name(namestart)
835 sg_desc = sg_name + " description"
836 sg_dict = dict(name=sg_name,
837 description=sg_desc)
838 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500839 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300840 secgroup = net_resources.DeletableSecurityGroup(
841 client=client,
842 **result['security_group']
843 )
844 self.assertEqual(secgroup.name, sg_name)
845 self.assertEqual(tenant_id, secgroup.tenant_id)
846 self.assertEqual(secgroup.description, sg_desc)
847 self.addCleanup(self.delete_wrapper, secgroup.delete)
848 return secgroup
849
Yair Frieddb6c9e92014-08-06 08:53:13 +0300850 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300851 """Get default secgroup for given tenant_id.
852
853 :returns: DeletableSecurityGroup -- default secgroup for given tenant
854 """
855 if client is None:
856 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300857 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000858 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300859 sgs = [
860 sg for sg in client.list_security_groups().values()[0]
861 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
862 ]
863 msg = "No default security group for tenant %s." % (tenant_id)
864 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300865 return net_resources.DeletableSecurityGroup(client=client,
866 **sgs[0])
867
Yair Frieddb6c9e92014-08-06 08:53:13 +0300868 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300869 tenant_id=None, **kwargs):
870 """Create a rule from a dictionary of rule parameters.
871
872 Create a rule in a secgroup. if secgroup not defined will search for
873 default secgroup in tenant_id.
874
875 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300876 :param tenant_id: if secgroup not passed -- the tenant in which to
877 search for default secgroup
878 :param kwargs: a dictionary containing rule parameters:
879 for example, to allow incoming ssh:
880 rule = {
881 direction: 'ingress'
882 protocol:'tcp',
883 port_range_min: 22,
884 port_range_max: 22
885 }
886 """
887 if client is None:
888 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300889 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000890 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300891 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300892 secgroup = self._default_security_group(client=client,
893 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300894
895 ruleset = dict(security_group_id=secgroup.id,
896 tenant_id=secgroup.tenant_id)
897 ruleset.update(kwargs)
898
David Kranz34e88122014-12-11 15:24:05 -0500899 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300900 sg_rule = net_resources.DeletableSecurityGroupRule(
901 client=client,
902 **sg_rule['security_group_rule']
903 )
904 self.addCleanup(self.delete_wrapper, sg_rule.delete)
905 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
906 self.assertEqual(secgroup.id, sg_rule.security_group_id)
907
908 return sg_rule
909
910 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
911 """These rules are intended to permit inbound ssh and icmp
912 traffic from all sources, so no group_id is provided.
913 Setting a group_id would only permit traffic from ports
914 belonging to the same security group.
915 """
916
917 if client is None:
918 client = self.network_client
919 rules = []
920 rulesets = [
921 dict(
922 # ssh
923 protocol='tcp',
924 port_range_min=22,
925 port_range_max=22,
926 ),
927 dict(
928 # ping
929 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +0100930 ),
931 dict(
932 # ipv6-icmp for ping6
933 protocol='icmp',
934 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +0300935 )
936 ]
937 for ruleset in rulesets:
938 for r_direction in ['ingress', 'egress']:
939 ruleset['direction'] = r_direction
940 try:
941 sg_rule = self._create_security_group_rule(
942 client=client, secgroup=secgroup, **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +0900943 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +0300944 # if rule already exist - skip rule and continue
945 msg = 'Security group rule already exists'
946 if msg not in ex._error_string:
947 raise ex
948 else:
949 self.assertEqual(r_direction, sg_rule.direction)
950 rules.append(sg_rule)
951
952 return rules
953
954 def _ssh_to_server(self, server, private_key):
955 ssh_login = CONF.compute.image_ssh_user
956 return self.get_remote_client(server,
957 username=ssh_login,
958 private_key=private_key)
959
Yair Frieddb6c9e92014-08-06 08:53:13 +0300960 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300961 """Retrieve a router for the given tenant id.
962
963 If a public router has been configured, it will be returned.
964
965 If a public router has not been configured, but a public
966 network has, a tenant router will be created and returned that
967 routes traffic to the public network.
968 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300969 if not client:
970 client = self.network_client
971 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000972 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300973 router_id = CONF.network.public_router_id
974 network_id = CONF.network.public_network_id
975 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -0400976 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +0400977 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300978 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300979 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300980 router.set_gateway(network_id)
981 return router
982 else:
983 raise Exception("Neither of 'public_router_id' or "
984 "'public_network_id' has been defined.")
985
Yair Frieddb6c9e92014-08-06 08:53:13 +0300986 def _create_router(self, client=None, tenant_id=None,
987 namestart='router-smoke'):
988 if not client:
989 client = self.network_client
990 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000991 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300992 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500993 result = client.create_router(name=name,
994 admin_state_up=True,
995 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300996 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300997 **result['router'])
998 self.assertEqual(router.name, name)
999 self.addCleanup(self.delete_wrapper, router.delete)
1000 return router
1001
Alok Maurya6384bbb2014-07-13 06:44:29 -07001002 def _update_router_admin_state(self, router, admin_state_up):
1003 router.update(admin_state_up=admin_state_up)
1004 self.assertEqual(admin_state_up, router.admin_state_up)
1005
Yair Fried413bf2d2014-11-19 17:07:11 +02001006 def create_networks(self, client=None, tenant_id=None,
1007 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001008 """Create a network with a subnet connected to a router.
1009
David Shrewsbury9bac3662014-08-07 15:07:01 -04001010 The baremetal driver is a special case since all nodes are
1011 on the same shared network.
1012
Yair Fried413bf2d2014-11-19 17:07:11 +02001013 :param client: network client to create resources with.
1014 :param tenant_id: id of tenant to create resources in.
1015 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001016 :returns: network, subnet, router
1017 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001018 if CONF.baremetal.driver_enabled:
1019 # NOTE(Shrews): This exception is for environments where tenant
1020 # credential isolation is available, but network separation is
1021 # not (the current baremetal case). Likely can be removed when
1022 # test account mgmt is reworked:
1023 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001024 if not CONF.compute.fixed_network_name:
1025 m = 'fixed_network_name must be specified in config'
1026 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001027 network = self._get_network_by_name(
1028 CONF.compute.fixed_network_name)
1029 router = None
1030 subnet = None
1031 else:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001032 network = self._create_network(client=client, tenant_id=tenant_id)
1033 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001034
1035 subnet_kwargs = dict(network=network, client=client)
1036 # use explicit check because empty list is a valid option
1037 if dns_nameservers is not None:
1038 subnet_kwargs['dns_nameservers'] = dns_nameservers
1039 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001040 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001041 return network, subnet, router
1042
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001043 def create_server(self, name=None, image=None, flavor=None,
1044 wait_on_boot=True, wait_on_delete=True,
1045 create_kwargs=None):
1046 vnic_type = CONF.network.port_vnic_type
1047
1048 # If vnic_type is configured create port for
1049 # every network
1050 if vnic_type:
1051 ports = []
1052 networks = []
1053 create_port_body = {'binding:vnic_type': vnic_type,
1054 'namestart': 'port-smoke'}
1055 if create_kwargs:
1056 net_client = create_kwargs.get("network_client",
1057 self.network_client)
1058
1059 # Convert security group names to security group ids
1060 # to pass to create_port
1061 if create_kwargs.get('security_groups'):
1062 security_groups = net_client.list_security_groups().get(
1063 'security_groups')
1064 sec_dict = dict([(s['name'], s['id'])
1065 for s in security_groups])
1066
1067 sec_groups_names = [s['name'] for s in create_kwargs[
1068 'security_groups']]
1069 security_groups_ids = [sec_dict[s]
1070 for s in sec_groups_names]
1071
1072 if security_groups_ids:
1073 create_port_body[
1074 'security_groups'] = security_groups_ids
1075 networks = create_kwargs.get('networks')
1076 else:
1077 net_client = self.network_client
1078 # If there are no networks passed to us we look up
1079 # for the tenant's private networks and create a port
1080 # if there is only one private network. The same behaviour
1081 # as we would expect when passing the call to the clients
1082 # with no networks
1083 if not networks:
1084 networks = net_client.list_networks(filters={
1085 'router:external': False})
1086 self.assertEqual(1, len(networks),
1087 "There is more than one"
1088 " network for the tenant")
1089 for net in networks:
1090 net_id = net['uuid']
1091 port = self._create_port(network_id=net_id,
1092 client=net_client,
1093 **create_port_body)
1094 ports.append({'port': port.id})
1095 if ports:
1096 create_kwargs['networks'] = ports
1097
1098 return super(NetworkScenarioTest, self).create_server(
1099 name=name, image=image, flavor=flavor,
1100 wait_on_boot=wait_on_boot, wait_on_delete=wait_on_delete,
1101 create_kwargs=create_kwargs)
1102
Yair Fried1fc32a12014-08-04 09:11:30 +03001103
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001104# power/provision states as of icehouse
1105class BaremetalPowerStates(object):
1106 """Possible power states of an Ironic node."""
1107 POWER_ON = 'power on'
1108 POWER_OFF = 'power off'
1109 REBOOT = 'rebooting'
1110 SUSPEND = 'suspended'
1111
1112
1113class BaremetalProvisionStates(object):
1114 """Possible provision states of an Ironic node."""
1115 NOSTATE = None
1116 INIT = 'initializing'
1117 ACTIVE = 'active'
1118 BUILDING = 'building'
1119 DEPLOYWAIT = 'wait call-back'
1120 DEPLOYING = 'deploying'
1121 DEPLOYFAIL = 'deploy failed'
1122 DEPLOYDONE = 'deploy complete'
1123 DELETING = 'deleting'
1124 DELETED = 'deleted'
1125 ERROR = 'error'
1126
1127
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001128class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001129
1130 credentials = ['primary', 'admin']
1131
Adam Gandelman4a48a602014-03-20 18:23:18 -07001132 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001133 def skip_checks(cls):
1134 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001135 if (not CONF.service_available.ironic or
1136 not CONF.baremetal.driver_enabled):
1137 msg = 'Ironic not available or Ironic compute driver not enabled'
1138 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001139
1140 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001141 def setup_clients(cls):
1142 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001143
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001144 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001145
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001146 @classmethod
1147 def resource_setup(cls):
1148 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001149 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001150 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001151
1152 def _node_state_timeout(self, node_id, state_attr,
1153 target_states, timeout=10, interval=1):
1154 if not isinstance(target_states, list):
1155 target_states = [target_states]
1156
1157 def check_state():
1158 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001159 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001160 return True
1161 return False
1162
1163 if not tempest.test.call_until_true(
1164 check_state, timeout, interval):
1165 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1166 (node_id, state_attr, target_states))
1167 raise exceptions.TimeoutException(msg)
1168
1169 def wait_provisioning_state(self, node_id, state, timeout):
1170 self._node_state_timeout(
1171 node_id=node_id, state_attr='provision_state',
1172 target_states=state, timeout=timeout)
1173
1174 def wait_power_state(self, node_id, state):
1175 self._node_state_timeout(
1176 node_id=node_id, state_attr='power_state',
1177 target_states=state, timeout=CONF.baremetal.power_timeout)
1178
1179 def wait_node(self, instance_id):
1180 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001181
Adam Gandelman4a48a602014-03-20 18:23:18 -07001182 def _get_node():
1183 node = None
1184 try:
1185 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001186 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001187 pass
1188 return node is not None
1189
1190 if not tempest.test.call_until_true(
1191 _get_node, CONF.baremetal.association_timeout, 1):
1192 msg = ('Timed out waiting to get Ironic node by instance id %s'
1193 % instance_id)
1194 raise exceptions.TimeoutException(msg)
1195
1196 def get_node(self, node_id=None, instance_id=None):
1197 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001198 _, body = self.baremetal_client.show_node(node_id)
1199 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001200 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001201 _, body = self.baremetal_client.show_node_by_instance_uuid(
1202 instance_id)
1203 if body['nodes']:
1204 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001205
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001206 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001207 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001208 _, body = self.baremetal_client.list_node_ports(node_uuid)
1209 for port in body['ports']:
1210 _, p = self.baremetal_client.show_port(port['uuid'])
1211 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001212 return ports
1213
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001214 def add_keypair(self):
1215 self.keypair = self.create_keypair()
1216
1217 def verify_connectivity(self, ip=None):
1218 if ip:
1219 dest = self.get_remote_client(ip)
1220 else:
1221 dest = self.get_remote_client(self.instance)
1222 dest.validate_authentication()
1223
1224 def boot_instance(self):
1225 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001226 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001227 }
1228 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001229 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001230
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001231 self.wait_node(self.instance['id'])
1232 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001233
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001234 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001235
1236 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001237 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001238 [BaremetalProvisionStates.DEPLOYWAIT,
1239 BaremetalProvisionStates.ACTIVE],
1240 timeout=15)
1241
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001242 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001243 BaremetalProvisionStates.ACTIVE,
1244 timeout=CONF.baremetal.active_timeout)
1245
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001246 waiters.wait_for_server_status(self.servers_client,
1247 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001248 self.node = self.get_node(instance_id=self.instance['id'])
Ken'ichi Ohmichi76800242015-07-03 05:12:31 +00001249 self.instance = self.servers_client.show_server(self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001250
1251 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001252 self.servers_client.delete_server(self.instance['id'])
1253 self.wait_power_state(self.node['uuid'],
1254 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001255 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001256 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001257 BaremetalProvisionStates.NOSTATE,
1258 timeout=CONF.baremetal.unprovision_timeout)
1259
Adam Gandelman4a48a602014-03-20 18:23:18 -07001260
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001261class EncryptionScenarioTest(ScenarioTest):
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001262 """
1263 Base class for encryption scenario tests
1264 """
1265
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001266 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001267
1268 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001269 def setup_clients(cls):
1270 super(EncryptionScenarioTest, cls).setup_clients()
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001271 cls.admin_volume_types_client = cls.os_adm.volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001272
1273 def _wait_for_volume_status(self, status):
1274 self.status_timeout(
1275 self.volume_client.volumes, self.volume.id, status)
1276
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001277 def nova_boot(self):
1278 self.keypair = self.create_keypair()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001279 create_kwargs = {'key_name': self.keypair['name']}
1280 self.server = self.create_server(image=self.image,
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001281 create_kwargs=create_kwargs)
1282
1283 def create_volume_type(self, client=None, name=None):
1284 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001285 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001286 if not name:
1287 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001288 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001289 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001290 body = client.create_volume_type(
John Warrend053ded2015-08-13 15:22:48 +00001291 randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001292 self.assertIn('id', body)
1293 self.addCleanup(client.delete_volume_type, body['id'])
1294 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001295
1296 def create_encryption_type(self, client=None, type_id=None, provider=None,
1297 key_size=None, cipher=None,
1298 control_location=None):
1299 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001300 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001301 if not type_id:
1302 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001303 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001304 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001305 client.create_encryption_type(
1306 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001307 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001308
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001309
Chris Dent0d494112014-08-26 13:48:30 +01001310class SwiftScenarioTest(ScenarioTest):
1311 """
1312 Provide harness to do Swift scenario tests.
1313
1314 Subclasses implement the tests that use the methods provided by this
1315 class.
1316 """
1317
1318 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001319 def skip_checks(cls):
1320 super(SwiftScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001321 if not CONF.service_available.swift:
1322 skip_msg = ("%s skipped as swift is not available" %
1323 cls.__name__)
1324 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001325
1326 @classmethod
1327 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001328 cls.set_network_resources()
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001329 super(SwiftScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001330 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001331 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001332
1333 @classmethod
1334 def setup_clients(cls):
1335 super(SwiftScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001336 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001337 cls.account_client = cls.os_operator.account_client
1338 cls.container_client = cls.os_operator.container_client
1339 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001340
Chris Dentde456a12014-09-10 12:41:15 +01001341 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001342 """get swift status for our user account."""
1343 self.account_client.list_account_containers()
1344 LOG.debug('Swift status information obtained successfully')
1345
Chris Dentde456a12014-09-10 12:41:15 +01001346 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001347 name = container_name or data_utils.rand_name(
1348 'swift-scenario-container')
1349 self.container_client.create_container(name)
1350 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001351 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001352 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001353 self.addCleanup(self.delete_wrapper,
1354 self.container_client.delete_container,
1355 name)
Chris Dent0d494112014-08-26 13:48:30 +01001356 return name
1357
Chris Dentde456a12014-09-10 12:41:15 +01001358 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001359 self.container_client.delete_container(container_name)
1360 LOG.debug('Container %s deleted' % (container_name))
1361
Chris Dentde456a12014-09-10 12:41:15 +01001362 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001363 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1364 obj_data = data_utils.arbitrary_string()
1365 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001366 self.addCleanup(self.delete_wrapper,
1367 self.object_client.delete_object,
1368 container_name,
1369 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001370 return obj_name, obj_data
1371
Chris Dentde456a12014-09-10 12:41:15 +01001372 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001373 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001374 self.list_and_check_container_objects(container_name,
1375 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001376
Chris Dentde456a12014-09-10 12:41:15 +01001377 def list_and_check_container_objects(self, container_name,
1378 present_obj=None,
1379 not_present_obj=None):
Chris Dent0d494112014-08-26 13:48:30 +01001380 """
1381 List objects for a given container and assert which are present and
1382 which are not.
1383 """
Ghanshyam2a180b82014-06-16 13:54:22 +09001384 if present_obj is None:
1385 present_obj = []
1386 if not_present_obj is None:
1387 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001388 _, object_list = self.container_client.list_container_contents(
1389 container_name)
1390 if present_obj:
1391 for obj in present_obj:
1392 self.assertIn(obj, object_list)
1393 if not_present_obj:
1394 for obj in not_present_obj:
1395 self.assertNotIn(obj, object_list)
1396
Chris Dentde456a12014-09-10 12:41:15 +01001397 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001398 metadata_param = {'metadata_prefix': 'x-container-',
1399 'metadata': {'read': acl}}
1400 self.container_client.update_container_metadata(container_name,
1401 **metadata_param)
1402 resp, _ = self.container_client.list_container_metadata(container_name)
1403 self.assertEqual(resp['x-container-read'], acl)
1404
Chris Dentde456a12014-09-10 12:41:15 +01001405 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001406 _, obj = self.object_client.get_object(container_name, obj_name)
1407 self.assertEqual(obj, expected_data)