blob: b446807a86170975754ce294ef9b4fa732c12568 [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
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +030021from oslo_serialization import jsonutils as json
Matthew Treinish96e9e882014-06-09 18:37:19 -040022import six
Matt Riedemann5f0ac522015-05-21 09:16:24 -070023from tempest_lib.common.utils import misc as misc_utils
Masayuki Igawad9388762015-01-20 14:56:42 +090024from tempest_lib import exceptions as lib_exc
Sean Dague6dbc6da2013-05-08 17:49:46 -040025
Rohan Kanade9ce97df2013-12-10 18:59:35 +053026from tempest.common import fixed_network
Fei Long Wangd39431f2015-05-14 11:30:48 +120027from tempest.common.utils import data_utils
Masayuki Igawa4ded9f02014-02-17 15:05:59 +090028from tempest.common.utils.linux import remote_client
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +000029from tempest.common import waiters
Matthew Treinish6c072292014-01-29 19:15:52 +000030from tempest import config
Giulio Fidente92f77192013-08-26 17:13:28 +020031from tempest import exceptions
Yair Fried1fc32a12014-08-04 09:11:30 +030032from tempest.services.network import resources as net_resources
Sean Dague6dbc6da2013-05-08 17:49:46 -040033import tempest.test
Sean Dague6dbc6da2013-05-08 17:49:46 -040034
Matthew Treinish6c072292014-01-29 19:15:52 +000035CONF = config.CONF
Sean Dague6dbc6da2013-05-08 17:49:46 -040036
Attila Fazekasfb7552a2013-08-27 13:02:26 +020037LOG = log.getLogger(__name__)
38
Sean Dague6dbc6da2013-05-08 17:49:46 -040039
Andrea Frittoli2e733b52014-07-16 14:12:11 +010040class ScenarioTest(tempest.test.BaseTestCase):
Andrea Frittoli486ede72014-09-25 11:50:05 +010041 """Base class for scenario tests. Uses tempest own clients. """
Andrea Frittoli2e733b52014-07-16 14:12:11 +010042
Andrea Frittolib21de6c2015-02-06 20:12:38 +000043 credentials = ['primary']
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +000044
45 @classmethod
46 def setup_clients(cls):
47 super(ScenarioTest, cls).setup_clients()
Andrea Frittoli247058f2014-07-16 16:09:22 +010048 # Clients (in alphabetical order)
Adam Gandelmanc78c7572014-08-28 18:38:55 -070049 cls.flavors_client = cls.manager.flavors_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010050 cls.floating_ips_client = cls.manager.floating_ips_client
51 # Glance image client v1
52 cls.image_client = cls.manager.image_client
nithya-ganesan882595e2014-07-29 18:51:07 +000053 # Compute image client
54 cls.images_client = cls.manager.images_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010055 cls.keypairs_client = cls.manager.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010056 # Nova security groups client
57 cls.security_groups_client = cls.manager.security_groups_client
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +000058 cls.security_group_rules_client = (
59 cls.manager.security_group_rules_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +010060 cls.servers_client = cls.manager.servers_client
Yair Fried1fc32a12014-08-04 09:11:30 +030061 cls.interface_client = cls.manager.interfaces_client
62 # Neutron network client
63 cls.network_client = cls.manager.network_client
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090064 # Heat client
65 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010066
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030067 if CONF.volume_feature_enabled.api_v1:
68 cls.volumes_client = cls.manager.volumes_client
69 cls.snapshots_client = cls.manager.snapshots_client
70 else:
71 cls.volumes_client = cls.manager.volumes_v2_client
72 cls.snapshots_client = cls.manager.snapshots_v2_client
73
Andrea Frittoli247058f2014-07-16 16:09:22 +010074 # ## Methods to handle sync and async deletes
75
76 def setUp(self):
77 super(ScenarioTest, self).setUp()
78 self.cleanup_waits = []
79 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
80 # because scenario tests in the same test class should not share
81 # resources. If resources were shared between test cases then it
82 # should be a single scenario test instead of multiples.
83
84 # NOTE(yfried): this list is cleaned at the end of test_methods and
85 # not at the end of the class
86 self.addCleanup(self._wait_for_cleanups)
87
Yair Fried1fc32a12014-08-04 09:11:30 +030088 def delete_wrapper(self, delete_thing, *args, **kwargs):
Andrea Frittoli247058f2014-07-16 16:09:22 +010089 """Ignores NotFound exceptions for delete operations.
90
Yair Fried1fc32a12014-08-04 09:11:30 +030091 @param delete_thing: delete method of a resource. method will be
92 executed as delete_thing(*args, **kwargs)
93
Andrea Frittoli247058f2014-07-16 16:09:22 +010094 """
95 try:
96 # Tempest clients return dicts, so there is no common delete
97 # method available. Using a callable instead
Yair Fried1fc32a12014-08-04 09:11:30 +030098 delete_thing(*args, **kwargs)
Masayuki Igawabfa07602015-01-20 18:47:17 +090099 except lib_exc.NotFound:
Andrea Frittoli247058f2014-07-16 16:09:22 +0100100 # If the resource is already missing, mission accomplished.
101 pass
102
103 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +0900104 cleanup_callable, cleanup_args=None,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000105 cleanup_kwargs=None, waiter_client=None):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700106 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100107
108 @param waiter_callable: callable to wait for the resource to delete
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000109 with the following waiter_client if specified.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100110 @param thing_id: the id of the resource to be cleaned-up
111 @param thing_id_param: the name of the id param in the waiter
112 @param cleanup_callable: method to load pass to self.addCleanup with
113 the following *cleanup_args, **cleanup_kwargs.
114 usually a delete method.
115 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900116 if cleanup_args is None:
117 cleanup_args = []
118 if cleanup_kwargs is None:
119 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100120 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
121 wait_dict = {
122 'waiter_callable': waiter_callable,
123 thing_id_param: thing_id
124 }
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000125 if waiter_client:
126 wait_dict['client'] = waiter_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100127 self.cleanup_waits.append(wait_dict)
128
129 def _wait_for_cleanups(self):
130 """To handle async delete actions, a list of waits is added
131 which will be iterated over as the last step of clearing the
132 cleanup queue. That way all the delete calls are made up front
133 and the tests won't succeed unless the deletes are eventually
134 successful. This is the same basic approach used in the api tests to
135 limit cleanup execution time except here it is multi-resource,
136 because of the nature of the scenario tests.
137 """
138 for wait in self.cleanup_waits:
139 waiter_callable = wait.pop('waiter_callable')
140 waiter_callable(**wait)
141
142 # ## Test functions library
143 #
144 # The create_[resource] functions only return body and discard the
145 # resp part which is not used in scenario tests
146
Yair Frieddb6c9e92014-08-06 08:53:13 +0300147 def create_keypair(self, client=None):
148 if not client:
149 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100150 name = data_utils.rand_name(self.__class__.__name__)
151 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000152 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300153 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900154 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100155
156 def create_server(self, name=None, image=None, flavor=None,
157 wait_on_boot=True, wait_on_delete=True,
Ghanshyam2a180b82014-06-16 13:54:22 +0900158 create_kwargs=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100159 """Creates VM instance.
160
161 @param image: image from which to create the instance
162 @param wait_on_boot: wait for status ACTIVE before continue
163 @param wait_on_delete: force synchronous delete on cleanup
164 @param create_kwargs: additional details for instance creation
165 @return: server dict
166 """
167 if name is None:
168 name = data_utils.rand_name(self.__class__.__name__)
169 if image is None:
170 image = CONF.compute.image_ref
171 if flavor is None:
172 flavor = CONF.compute.flavor_ref
Ghanshyam2a180b82014-06-16 13:54:22 +0900173 if create_kwargs is None:
174 create_kwargs = {}
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530175 network = self.get_tenant_network()
Matthew Treinish4bbc1992015-04-07 11:13:40 -0400176 create_kwargs = fixed_network.set_networks_kwarg(network,
177 create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100178
Andrea Frittoli247058f2014-07-16 16:09:22 +0100179 LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
180 name, image, flavor)
David Kranz0fb14292015-02-11 15:55:20 -0500181 server = self.servers_client.create_server(name, image, flavor,
ghanshyam0f825252015-08-25 16:02:50 +0900182 **create_kwargs)['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100183 if wait_on_delete:
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000184 self.addCleanup(waiters.wait_for_server_termination,
185 self.servers_client,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100186 server['id'])
187 self.addCleanup_with_wait(
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000188 waiter_callable=waiters.wait_for_server_termination,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100189 thing_id=server['id'], thing_id_param='server_id',
190 cleanup_callable=self.delete_wrapper,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000191 cleanup_args=[self.servers_client.delete_server, server['id']],
192 waiter_client=self.servers_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100193 if wait_on_boot:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000194 waiters.wait_for_server_status(self.servers_client,
195 server_id=server['id'],
196 status='ACTIVE')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100197 # The instance retrieved on creation is missing network
198 # details, necessitating retrieval after it becomes active to
199 # ensure correct details.
ghanshyam0f825252015-08-25 16:02:50 +0900200 server = self.servers_client.show_server(server['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100201 self.assertEqual(server['name'], name)
202 return server
203
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100204 def create_volume(self, size=None, name=None, snapshot_id=None,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100205 imageRef=None, volume_type=None, wait_on_delete=True):
206 if name is None:
207 name = data_utils.rand_name(self.__class__.__name__)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000208 volume = self.volumes_client.create_volume(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100209 size=size, display_name=name, snapshot_id=snapshot_id,
John Warren6177c9e2015-08-19 20:00:17 +0000210 imageRef=imageRef, volume_type=volume_type)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700211
Andrea Frittoli247058f2014-07-16 16:09:22 +0100212 if wait_on_delete:
213 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
214 volume['id'])
Matt Riedemanne85c2702014-09-10 11:50:13 -0700215 self.addCleanup(self.delete_wrapper,
216 self.volumes_client.delete_volume, volume['id'])
217 else:
218 self.addCleanup_with_wait(
219 waiter_callable=self.volumes_client.wait_for_resource_deletion,
220 thing_id=volume['id'], thing_id_param='id',
221 cleanup_callable=self.delete_wrapper,
222 cleanup_args=[self.volumes_client.delete_volume, volume['id']])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100223
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300224 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
225 if 'display_name' in volume:
226 self.assertEqual(name, volume['display_name'])
227 else:
228 self.assertEqual(name, volume['name'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100229 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
230 # The volume retrieved on creation has a non-up-to-date status.
231 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000232 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100233 return volume
234
Yair Fried1fc32a12014-08-04 09:11:30 +0300235 def _create_loginable_secgroup_rule(self, secgroup_id=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100236 _client = self.security_groups_client
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000237 _client_rules = self.security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100238 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900239 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100240 for sg in sgs:
241 if sg['name'] == 'default':
242 secgroup_id = sg['id']
243
244 # These rules are intended to permit inbound ssh and icmp
245 # traffic from all sources, so no group_id is provided.
246 # Setting a group_id would only permit traffic from ports
247 # belonging to the same security group.
248 rulesets = [
249 {
250 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000251 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100252 'from_port': 22,
253 'to_port': 22,
254 'cidr': '0.0.0.0/0',
255 },
256 {
257 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000258 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100259 'from_port': -1,
260 'to_port': -1,
261 'cidr': '0.0.0.0/0',
262 }
263 ]
264 rules = list()
265 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000266 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900267 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100268 self.addCleanup(self.delete_wrapper,
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000269 _client_rules.delete_security_group_rule,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100270 sg_rule['id'])
271 rules.append(sg_rule)
272 return rules
273
Yair Fried1fc32a12014-08-04 09:11:30 +0300274 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100275 # Create security group
276 sg_name = data_utils.rand_name(self.__class__.__name__)
277 sg_desc = sg_name + " description"
David Kranz9964b4e2015-02-06 15:45:29 -0500278 secgroup = self.security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900279 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100280 self.assertEqual(secgroup['name'], sg_name)
281 self.assertEqual(secgroup['description'], sg_desc)
282 self.addCleanup(self.delete_wrapper,
283 self.security_groups_client.delete_security_group,
284 secgroup['id'])
285
286 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300287 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100288
289 return secgroup
290
JordanP3fe2dc32014-11-17 13:06:01 +0100291 def get_remote_client(self, server_or_ip, username=None, private_key=None,
292 log_console_of_servers=None):
293 """Get a SSH client to a remote server
294
295 @param server_or_ip a server object as returned by Tempest compute
296 client or an IP address to connect to
297 @param username name of the Linux account on the remote server
298 @param private_key the SSH private key to use
299 @param log_console_of_servers a list of server objects. Each server
300 in the list will have its console printed in the logs in case the
301 SSH connection failed to be established
302 @return a RemoteClient object
303 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100304 if isinstance(server_or_ip, six.string_types):
305 ip = server_or_ip
306 else:
Andrew Boik4a3daf12015-03-27 01:59:31 -0400307 addrs = server_or_ip['addresses'][CONF.compute.network_for_ssh]
308 try:
309 ip = (addr['addr'] for addr in addrs if
310 netaddr.valid_ipv4(addr['addr'])).next()
311 except StopIteration:
312 raise lib_exc.NotFound("No IPv4 addresses to use for SSH to "
313 "remote server.")
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700314
Andrea Frittoli247058f2014-07-16 16:09:22 +0100315 if username is None:
316 username = CONF.scenario.ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800317 # Set this with 'keypair' or others to log in with keypair or
318 # username/password.
319 if CONF.compute.ssh_auth_method == 'keypair':
320 password = None
321 if private_key is None:
322 private_key = self.keypair['private_key']
323 else:
324 password = CONF.compute.image_ssh_password
325 private_key = None
Andrea Frittoli247058f2014-07-16 16:09:22 +0100326 linux_client = remote_client.RemoteClient(ip, username,
wantwatering896300c2015-03-27 15:17:42 +0800327 pkey=private_key,
328 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100329 try:
330 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700331 except Exception as e:
332 message = ('Initializing SSH connection to %(ip)s failed. '
333 'Error: %(error)s' % {'ip': ip, 'error': e})
334 caller = misc_utils.find_test_caller()
335 if caller:
336 message = '(%s) %s' % (caller, message)
337 LOG.exception(message)
Marc Kodererb06db502015-04-30 09:31:27 +0200338 # If we don't explicitly set for which servers we want to
JordanP3fe2dc32014-11-17 13:06:01 +0100339 # log the console output then all the servers will be logged.
340 # See the definition of _log_console_output()
341 self._log_console_output(log_console_of_servers)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100342 raise
343
344 return linux_client
345
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000346 def _image_create(self, name, fmt, path,
347 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900348 if properties is None:
349 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100350 name = data_utils.rand_name('%s-' % name)
351 image_file = open(path, 'rb')
352 self.addCleanup(image_file.close)
353 params = {
354 'name': name,
355 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000356 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100357 'is_public': 'False',
358 }
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000359 params['properties'] = properties
John Warren66207252015-07-31 15:51:02 -0400360 image = self.image_client.create_image(**params)['image']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100361 self.addCleanup(self.image_client.delete_image, image['id'])
362 self.assertEqual("queued", image['status'])
363 self.image_client.update_image(image['id'], data=image_file)
364 return image['id']
365
366 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300367 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100368 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
369 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
370 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300371 img_container_format = CONF.scenario.img_container_format
372 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000373 img_properties = CONF.scenario.img_properties
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300374 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000375 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300376 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000377 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100378 try:
379 self.image = self._image_create('scenario-img',
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300380 img_container_format,
381 img_path,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000382 disk_format=img_disk_format,
383 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100384 except IOError:
385 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
386 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
387 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000388 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100389 self.image = self._image_create('scenario-ami', 'ami',
390 path=ami_img_path,
391 properties=properties)
392 LOG.debug("image:%s" % self.image)
393
394 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400395 if not CONF.compute_feature_enabled.console_output:
396 LOG.debug('Console output not supported, cannot log')
397 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100398 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500399 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100400 servers = servers['servers']
401 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500402 console_output = self.servers_client.get_console_output(
ghanshyam0f825252015-08-25 16:02:50 +0900403 server['id'], length=None)['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500404 LOG.debug('Console output for %s\nbody=\n%s',
405 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100406
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000407 def _log_net_info(self, exc):
408 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300409 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000410 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000411
nithya-ganesan882595e2014-07-29 18:51:07 +0000412 def create_server_snapshot(self, server, name=None):
413 # Glance client
414 _image_client = self.image_client
415 # Compute client
416 _images_client = self.images_client
417 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000418 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000419 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000420 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500421 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000422 _image_client.wait_for_image_status(image_id, 'active')
423 self.addCleanup_with_wait(
424 waiter_callable=_image_client.wait_for_resource_deletion,
425 thing_id=image_id, thing_id_param='id',
426 cleanup_callable=self.delete_wrapper,
427 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500428 snapshot_image = _image_client.get_image_meta(image_id)
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300429
430 bdm = snapshot_image.get('properties', {}).get('block_device_mapping')
431 if bdm:
432 bdm = json.loads(bdm)
433 if bdm and 'snapshot_id' in bdm[0]:
434 snapshot_id = bdm[0]['snapshot_id']
435 self.addCleanup(
436 self.snapshots_client.wait_for_resource_deletion,
437 snapshot_id)
438 self.addCleanup(
439 self.delete_wrapper, self.snapshots_client.delete_snapshot,
440 snapshot_id)
Andrey Pavlovd35957b2015-08-27 20:12:15 +0300441 self.snapshots_client.wait_for_snapshot_status(snapshot_id,
442 'available')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300443
nithya-ganesan882595e2014-07-29 18:51:07 +0000444 image_name = snapshot_image['name']
445 self.assertEqual(name, image_name)
446 LOG.debug("Created snapshot image %s for server %s",
447 image_name, server['name'])
448 return snapshot_image
449
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900450 def nova_volume_attach(self):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000451 volume = self.servers_client.attach_volume(
Ken'ichi Ohmichidfc88de2015-08-13 05:12:20 +0000452 self.server['id'], volumeId=self.volume['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900453 % CONF.compute.volume_device_name)['volumeAttachment']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900454 self.assertEqual(self.volume['id'], volume['id'])
455 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
456 # Refresh the volume after the attachment
John Warren6177c9e2015-08-19 20:00:17 +0000457 self.volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900458
459 def nova_volume_detach(self):
460 self.servers_client.detach_volume(self.server['id'], self.volume['id'])
461 self.volumes_client.wait_for_volume_status(self.volume['id'],
462 'available')
463
John Warren6177c9e2015-08-19 20:00:17 +0000464 volume = self.volumes_client.show_volume(self.volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900465 self.assertEqual('available', volume['status'])
466
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700467 def rebuild_server(self, server_id, image=None,
468 preserve_ephemeral=False, wait=True,
469 rebuild_kwargs=None):
470 if image is None:
471 image = CONF.compute.image_ref
472
473 rebuild_kwargs = rebuild_kwargs or {}
474
475 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
476 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000477 self.servers_client.rebuild_server(
478 server_id=server_id, image_ref=image,
479 preserve_ephemeral=preserve_ephemeral,
480 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700481 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000482 waiters.wait_for_server_status(self.servers_client,
483 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700484
Steven Hardyda2a8352014-10-02 12:52:20 +0100485 def ping_ip_address(self, ip_address, should_succeed=True,
486 ping_timeout=None):
487 timeout = ping_timeout or CONF.compute.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700488 cmd = ['ping', '-c1', '-w1', ip_address]
489
490 def ping():
491 proc = subprocess.Popen(cmd,
492 stdout=subprocess.PIPE,
493 stderr=subprocess.PIPE)
494 proc.communicate()
495 return (proc.returncode == 0) == should_succeed
496
Steven Hardyda2a8352014-10-02 12:52:20 +0100497 return tempest.test.call_until_true(ping, timeout, 1)
Aaron Rosena7df13b2014-09-23 09:45:45 -0700498
Yair Friedae0e73d2014-11-24 11:56:26 +0200499 def check_vm_connectivity(self, ip_address,
500 username=None,
501 private_key=None,
502 should_connect=True):
503 """
504 :param ip_address: server to test against
505 :param username: server's ssh username
506 :param private_key: server's ssh private key to be used
507 :param should_connect: True/False indicates positive/negative test
508 positive - attempt ping and ssh
509 negative - attempt ping and fail if succeed
510
511 :raises: AssertError if the result of the connectivity check does
512 not match the value of the should_connect param
513 """
514 if should_connect:
515 msg = "Timed out waiting for %s to become reachable" % ip_address
516 else:
517 msg = "ip address %s is reachable" % ip_address
518 self.assertTrue(self.ping_ip_address(ip_address,
519 should_succeed=should_connect),
520 msg=msg)
521 if should_connect:
522 # no need to check ssh for negative connectivity
523 self.get_remote_client(ip_address, username, private_key)
524
525 def check_public_network_connectivity(self, ip_address, username,
526 private_key, should_connect=True,
527 msg=None, servers=None):
528 # The target login is assumed to have been configured for
529 # key-based authentication by cloud-init.
530 LOG.debug('checking network connections to IP %s with user: %s' %
531 (ip_address, username))
532 try:
533 self.check_vm_connectivity(ip_address,
534 username,
535 private_key,
536 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500537 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200538 ex_msg = 'Public network connectivity check failed'
539 if msg:
540 ex_msg += ": " + msg
541 LOG.exception(ex_msg)
542 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200543 raise
544
545 def create_floating_ip(self, thing, pool_name=None):
546 """Creates a floating IP and associates to a server using
547 Nova clients
548 """
549
ghanshyam9a3a9a22015-08-18 17:03:55 +0900550 floating_ip = (self.floating_ips_client.create_floating_ip(pool_name)
551 ['floating_ip'])
Yair Friedae0e73d2014-11-24 11:56:26 +0200552 self.addCleanup(self.delete_wrapper,
553 self.floating_ips_client.delete_floating_ip,
554 floating_ip['id'])
555 self.floating_ips_client.associate_floating_ip_to_server(
556 floating_ip['ip'], thing['id'])
557 return floating_ip
558
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100559
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100560class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300561 """Base class for network scenario tests.
562 This class provide helpers for network scenario tests, using the neutron
563 API. Helpers from ancestor which use the nova network API are overridden
564 with the neutron API.
565
566 This Class also enforces using Neutron instead of novanetwork.
567 Subclassed tests will be skipped if Neutron is not enabled
568
569 """
570
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000571 credentials = ['primary', 'admin']
572
Yair Fried1fc32a12014-08-04 09:11:30 +0300573 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000574 def skip_checks(cls):
575 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100576 if not CONF.service_available.neutron:
577 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300578
579 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100580 def resource_setup(cls):
581 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300582 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300583
Yair Frieddb6c9e92014-08-06 08:53:13 +0300584 def _create_network(self, client=None, tenant_id=None,
585 namestart='network-smoke-'):
586 if not client:
587 client = self.network_client
588 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000589 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300590 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500591 result = client.create_network(name=name, tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300592 network = net_resources.DeletableNetwork(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300593 **result['network'])
594 self.assertEqual(network.name, name)
595 self.addCleanup(self.delete_wrapper, network.delete)
596 return network
597
598 def _list_networks(self, *args, **kwargs):
599 """List networks using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900600 networks_list = self.admin_manager.network_client.list_networks(
601 *args, **kwargs)
602 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300603
604 def _list_subnets(self, *args, **kwargs):
605 """List subnets using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900606 subnets_list = self.admin_manager.network_client.list_subnets(
607 *args, **kwargs)
608 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300609
610 def _list_routers(self, *args, **kwargs):
611 """List routers using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900612 routers_list = self.admin_manager.network_client.list_routers(
613 *args, **kwargs)
614 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300615
616 def _list_ports(self, *args, **kwargs):
617 """List ports using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900618 ports_list = self.admin_manager.network_client.list_ports(
619 *args, **kwargs)
620 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300621
Yair Fried564d89d2015-08-06 17:02:12 +0300622 def _list_agents(self, *args, **kwargs):
623 """List agents using admin creds """
624 agents_list = self.admin_manager.network_client.list_agents(
625 *args, **kwargs)
626 return agents_list['agents']
627
Yair Frieddb6c9e92014-08-06 08:53:13 +0300628 def _create_subnet(self, network, client=None, namestart='subnet-smoke',
629 **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300630 """
631 Create a subnet for the given network within the cidr block
632 configured for tenant networks.
633 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300634 if not client:
635 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300636
637 def cidr_in_use(cidr, tenant_id):
638 """
639 :return True if subnet with cidr already exist in tenant
640 False else
641 """
642 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
643 return len(cidr_in_use) != 0
644
Kirill Shileev14113572014-11-21 16:58:02 +0300645 ip_version = kwargs.pop('ip_version', 4)
646
647 if ip_version == 6:
648 tenant_cidr = netaddr.IPNetwork(
649 CONF.network.tenant_network_v6_cidr)
650 num_bits = CONF.network.tenant_network_v6_mask_bits
651 else:
652 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
653 num_bits = CONF.network.tenant_network_mask_bits
654
Yair Fried1fc32a12014-08-04 09:11:30 +0300655 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300656 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300657 # Repeatedly attempt subnet creation with sequential cidr
658 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300659 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300660 str_cidr = str(subnet_cidr)
661 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
662 continue
663
664 subnet = dict(
665 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300666 network_id=network.id,
667 tenant_id=network.tenant_id,
668 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300669 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300670 **kwargs
671 )
672 try:
David Kranz34e88122014-12-11 15:24:05 -0500673 result = client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300674 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900675 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300676 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
677 if not is_overlapping_cidr:
678 raise
679 self.assertIsNotNone(result, 'Unable to allocate tenant network')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300680 subnet = net_resources.DeletableSubnet(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300681 **result['subnet'])
682 self.assertEqual(subnet.cidr, str_cidr)
683 self.addCleanup(self.delete_wrapper, subnet.delete)
684 return subnet
685
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200686 def _create_port(self, network_id, client=None, namestart='port-quotatest',
687 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300688 if not client:
689 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300690 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500691 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300692 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200693 network_id=network_id,
694 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300695 self.assertIsNotNone(result, 'Unable to allocate port')
Yair Frieddb6c9e92014-08-06 08:53:13 +0300696 port = net_resources.DeletablePort(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300697 **result['port'])
698 self.addCleanup(self.delete_wrapper, port.delete)
699 return port
700
Kirill Shileev14113572014-11-21 16:58:02 +0300701 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300702 ports = self._list_ports(device_id=server['id'],
703 fixed_ip=ip_addr)
Kirill Shileev14113572014-11-21 16:58:02 +0300704 # it might happen here that this port has more then one ip address
705 # as in case of dual stack- when this port is created on 2 subnets
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200706 port_map = [(p["id"], fxip["ip_address"])
707 for p in ports
708 for fxip in p["fixed_ips"]
709 if netaddr.valid_ipv4(fxip["ip_address"])]
710
711 self.assertEqual(len(port_map), 1,
712 "Found multiple IPv4 addresses: %s. "
713 "Unable to determine which port to target."
714 % port_map)
715 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300716
David Shrewsbury9bac3662014-08-07 15:07:01 -0400717 def _get_network_by_name(self, network_name):
718 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700719 self.assertNotEqual(len(net), 0,
720 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300721 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400722
Yair Friedae0e73d2014-11-24 11:56:26 +0200723 def create_floating_ip(self, thing, external_network_id=None,
724 port_id=None, client=None):
725 """Creates a floating IP and associates to a resource/port using
726 Neutron client
727 """
728 if not external_network_id:
729 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300730 if not client:
731 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300732 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300733 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
734 else:
735 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500736 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300737 floating_network_id=external_network_id,
738 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300739 tenant_id=thing['tenant_id'],
740 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300741 )
742 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300743 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300744 **result['floatingip'])
745 self.addCleanup(self.delete_wrapper, floating_ip.delete)
746 return floating_ip
747
748 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300749 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300750 floating_ip.update(port_id=port_id)
751 self.assertEqual(port_id, floating_ip.port_id)
752 return floating_ip
753
754 def _disassociate_floating_ip(self, floating_ip):
755 """
756 :param floating_ip: type DeletableFloatingIp
757 """
758 floating_ip.update(port_id=None)
759 self.assertIsNone(floating_ip.port_id)
760 return floating_ip
761
Yair Fried45f92952014-06-26 05:19:19 +0300762 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000763 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300764
765 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
766 to check status
767 :param status: target status
768 :raises: AssertionError if status doesn't match
769 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000770 def refresh():
771 floating_ip.refresh()
772 return status == floating_ip.status
773
774 tempest.test.call_until_true(refresh,
775 CONF.network.build_timeout,
776 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300777 self.assertEqual(status, floating_ip.status,
778 message="FloatingIP: {fp} is at status: {cst}. "
779 "failed to reach status: {st}"
780 .format(fp=floating_ip, cst=floating_ip.status,
781 st=status))
782 LOG.info("FloatingIP: {fp} is at status: {st}"
783 .format(fp=floating_ip, st=status))
784
Yair Fried1fc32a12014-08-04 09:11:30 +0300785 def _check_tenant_network_connectivity(self, server,
786 username,
787 private_key,
788 should_connect=True,
789 servers_for_debug=None):
790 if not CONF.network.tenant_networks_reachable:
791 msg = 'Tenant networks not configured to be reachable.'
792 LOG.info(msg)
793 return
794 # The target login is assumed to have been configured for
795 # key-based authentication by cloud-init.
796 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400797 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300798 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900799 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200800 username,
801 private_key,
802 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300803 except Exception as e:
804 LOG.exception('Tenant network connectivity check failed')
805 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000806 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300807 raise
808
809 def _check_remote_connectivity(self, source, dest, should_succeed=True):
810 """
811 check ping server via source ssh connection
812
813 :param source: RemoteClient: an ssh connection from which to ping
814 :param dest: and IP to ping against
815 :param should_succeed: boolean should ping succeed or not
816 :returns: boolean -- should_succeed == ping
817 :returns: ping is false if ping failed
818 """
819 def ping_remote():
820 try:
821 source.ping_host(dest)
Andrey Pavlov64723762015-04-29 06:24:58 +0300822 except lib_exc.SSHExecCommandFailed:
Yair Fried1fc32a12014-08-04 09:11:30 +0300823 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
824 % (dest, source.ssh_client.host))
825 return not should_succeed
826 return should_succeed
827
828 return tempest.test.call_until_true(ping_remote,
829 CONF.compute.ping_timeout,
830 1)
831
Yair Frieddb6c9e92014-08-06 08:53:13 +0300832 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300833 namestart='secgroup-smoke'):
834 if client is None:
835 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300836 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000837 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300838 secgroup = self._create_empty_security_group(namestart=namestart,
839 client=client,
840 tenant_id=tenant_id)
841
842 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900843 rules = self._create_loginable_secgroup_rule(client=client,
844 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300845 for rule in rules:
846 self.assertEqual(tenant_id, rule.tenant_id)
847 self.assertEqual(secgroup.id, rule.security_group_id)
848 return secgroup
849
Yair Frieddb6c9e92014-08-06 08:53:13 +0300850 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300851 namestart='secgroup-smoke'):
852 """Create a security group without rules.
853
854 Default rules will be created:
855 - IPv4 egress to any
856 - IPv6 egress to any
857
858 :param tenant_id: secgroup will be created in this tenant
859 :returns: DeletableSecurityGroup -- containing the secgroup created
860 """
861 if client is None:
862 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300863 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000864 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300865 sg_name = data_utils.rand_name(namestart)
866 sg_desc = sg_name + " description"
867 sg_dict = dict(name=sg_name,
868 description=sg_desc)
869 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500870 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300871 secgroup = net_resources.DeletableSecurityGroup(
872 client=client,
873 **result['security_group']
874 )
875 self.assertEqual(secgroup.name, sg_name)
876 self.assertEqual(tenant_id, secgroup.tenant_id)
877 self.assertEqual(secgroup.description, sg_desc)
878 self.addCleanup(self.delete_wrapper, secgroup.delete)
879 return secgroup
880
Yair Frieddb6c9e92014-08-06 08:53:13 +0300881 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300882 """Get default secgroup for given tenant_id.
883
884 :returns: DeletableSecurityGroup -- default secgroup for given tenant
885 """
886 if client is None:
887 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300888 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000889 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300890 sgs = [
891 sg for sg in client.list_security_groups().values()[0]
892 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
893 ]
894 msg = "No default security group for tenant %s." % (tenant_id)
895 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300896 return net_resources.DeletableSecurityGroup(client=client,
897 **sgs[0])
898
Yair Frieddb6c9e92014-08-06 08:53:13 +0300899 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300900 tenant_id=None, **kwargs):
901 """Create a rule from a dictionary of rule parameters.
902
903 Create a rule in a secgroup. if secgroup not defined will search for
904 default secgroup in tenant_id.
905
906 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300907 :param tenant_id: if secgroup not passed -- the tenant in which to
908 search for default secgroup
909 :param kwargs: a dictionary containing rule parameters:
910 for example, to allow incoming ssh:
911 rule = {
912 direction: 'ingress'
913 protocol:'tcp',
914 port_range_min: 22,
915 port_range_max: 22
916 }
917 """
918 if client is None:
919 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300920 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000921 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300922 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300923 secgroup = self._default_security_group(client=client,
924 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300925
926 ruleset = dict(security_group_id=secgroup.id,
927 tenant_id=secgroup.tenant_id)
928 ruleset.update(kwargs)
929
David Kranz34e88122014-12-11 15:24:05 -0500930 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300931 sg_rule = net_resources.DeletableSecurityGroupRule(
932 client=client,
933 **sg_rule['security_group_rule']
934 )
935 self.addCleanup(self.delete_wrapper, sg_rule.delete)
936 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
937 self.assertEqual(secgroup.id, sg_rule.security_group_id)
938
939 return sg_rule
940
941 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
942 """These rules are intended to permit inbound ssh and icmp
943 traffic from all sources, so no group_id is provided.
944 Setting a group_id would only permit traffic from ports
945 belonging to the same security group.
946 """
947
948 if client is None:
949 client = self.network_client
950 rules = []
951 rulesets = [
952 dict(
953 # ssh
954 protocol='tcp',
955 port_range_min=22,
956 port_range_max=22,
957 ),
958 dict(
959 # ping
960 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +0100961 ),
962 dict(
963 # ipv6-icmp for ping6
964 protocol='icmp',
965 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +0300966 )
967 ]
968 for ruleset in rulesets:
969 for r_direction in ['ingress', 'egress']:
970 ruleset['direction'] = r_direction
971 try:
972 sg_rule = self._create_security_group_rule(
973 client=client, secgroup=secgroup, **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +0900974 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +0300975 # if rule already exist - skip rule and continue
976 msg = 'Security group rule already exists'
977 if msg not in ex._error_string:
978 raise ex
979 else:
980 self.assertEqual(r_direction, sg_rule.direction)
981 rules.append(sg_rule)
982
983 return rules
984
985 def _ssh_to_server(self, server, private_key):
986 ssh_login = CONF.compute.image_ssh_user
987 return self.get_remote_client(server,
988 username=ssh_login,
989 private_key=private_key)
990
Yair Frieddb6c9e92014-08-06 08:53:13 +0300991 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300992 """Retrieve a router for the given tenant id.
993
994 If a public router has been configured, it will be returned.
995
996 If a public router has not been configured, but a public
997 network has, a tenant router will be created and returned that
998 routes traffic to the public network.
999 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001000 if not client:
1001 client = self.network_client
1002 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001003 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001004 router_id = CONF.network.public_router_id
1005 network_id = CONF.network.public_network_id
1006 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001007 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +04001008 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001009 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001010 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001011 router.set_gateway(network_id)
1012 return router
1013 else:
1014 raise Exception("Neither of 'public_router_id' or "
1015 "'public_network_id' has been defined.")
1016
Yair Frieddb6c9e92014-08-06 08:53:13 +03001017 def _create_router(self, client=None, tenant_id=None,
1018 namestart='router-smoke'):
1019 if not client:
1020 client = self.network_client
1021 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001022 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001023 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001024 result = client.create_router(name=name,
1025 admin_state_up=True,
1026 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001027 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001028 **result['router'])
1029 self.assertEqual(router.name, name)
1030 self.addCleanup(self.delete_wrapper, router.delete)
1031 return router
1032
Alok Maurya6384bbb2014-07-13 06:44:29 -07001033 def _update_router_admin_state(self, router, admin_state_up):
1034 router.update(admin_state_up=admin_state_up)
1035 self.assertEqual(admin_state_up, router.admin_state_up)
1036
Yair Fried413bf2d2014-11-19 17:07:11 +02001037 def create_networks(self, client=None, tenant_id=None,
1038 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001039 """Create a network with a subnet connected to a router.
1040
David Shrewsbury9bac3662014-08-07 15:07:01 -04001041 The baremetal driver is a special case since all nodes are
1042 on the same shared network.
1043
Yair Fried413bf2d2014-11-19 17:07:11 +02001044 :param client: network client to create resources with.
1045 :param tenant_id: id of tenant to create resources in.
1046 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001047 :returns: network, subnet, router
1048 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001049 if CONF.baremetal.driver_enabled:
1050 # NOTE(Shrews): This exception is for environments where tenant
1051 # credential isolation is available, but network separation is
1052 # not (the current baremetal case). Likely can be removed when
1053 # test account mgmt is reworked:
1054 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001055 if not CONF.compute.fixed_network_name:
1056 m = 'fixed_network_name must be specified in config'
1057 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001058 network = self._get_network_by_name(
1059 CONF.compute.fixed_network_name)
1060 router = None
1061 subnet = None
1062 else:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001063 network = self._create_network(client=client, tenant_id=tenant_id)
1064 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001065
1066 subnet_kwargs = dict(network=network, client=client)
1067 # use explicit check because empty list is a valid option
1068 if dns_nameservers is not None:
1069 subnet_kwargs['dns_nameservers'] = dns_nameservers
1070 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001071 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001072 return network, subnet, router
1073
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001074 def create_server(self, name=None, image=None, flavor=None,
1075 wait_on_boot=True, wait_on_delete=True,
1076 create_kwargs=None):
1077 vnic_type = CONF.network.port_vnic_type
1078
1079 # If vnic_type is configured create port for
1080 # every network
1081 if vnic_type:
1082 ports = []
1083 networks = []
1084 create_port_body = {'binding:vnic_type': vnic_type,
1085 'namestart': 'port-smoke'}
1086 if create_kwargs:
1087 net_client = create_kwargs.get("network_client",
1088 self.network_client)
1089
1090 # Convert security group names to security group ids
1091 # to pass to create_port
1092 if create_kwargs.get('security_groups'):
1093 security_groups = net_client.list_security_groups().get(
1094 'security_groups')
1095 sec_dict = dict([(s['name'], s['id'])
1096 for s in security_groups])
1097
1098 sec_groups_names = [s['name'] for s in create_kwargs[
1099 'security_groups']]
1100 security_groups_ids = [sec_dict[s]
1101 for s in sec_groups_names]
1102
1103 if security_groups_ids:
1104 create_port_body[
1105 'security_groups'] = security_groups_ids
1106 networks = create_kwargs.get('networks')
1107 else:
1108 net_client = self.network_client
1109 # If there are no networks passed to us we look up
1110 # for the tenant's private networks and create a port
1111 # if there is only one private network. The same behaviour
1112 # as we would expect when passing the call to the clients
1113 # with no networks
1114 if not networks:
1115 networks = net_client.list_networks(filters={
1116 'router:external': False})
1117 self.assertEqual(1, len(networks),
1118 "There is more than one"
1119 " network for the tenant")
1120 for net in networks:
1121 net_id = net['uuid']
1122 port = self._create_port(network_id=net_id,
1123 client=net_client,
1124 **create_port_body)
1125 ports.append({'port': port.id})
1126 if ports:
1127 create_kwargs['networks'] = ports
Shuquan Huangb5c8beb2015-08-05 14:14:01 +00001128 self.ports = ports
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001129
1130 return super(NetworkScenarioTest, self).create_server(
1131 name=name, image=image, flavor=flavor,
1132 wait_on_boot=wait_on_boot, wait_on_delete=wait_on_delete,
1133 create_kwargs=create_kwargs)
1134
Yair Fried1fc32a12014-08-04 09:11:30 +03001135
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001136# power/provision states as of icehouse
1137class BaremetalPowerStates(object):
1138 """Possible power states of an Ironic node."""
1139 POWER_ON = 'power on'
1140 POWER_OFF = 'power off'
1141 REBOOT = 'rebooting'
1142 SUSPEND = 'suspended'
1143
1144
1145class BaremetalProvisionStates(object):
1146 """Possible provision states of an Ironic node."""
1147 NOSTATE = None
1148 INIT = 'initializing'
1149 ACTIVE = 'active'
1150 BUILDING = 'building'
1151 DEPLOYWAIT = 'wait call-back'
1152 DEPLOYING = 'deploying'
1153 DEPLOYFAIL = 'deploy failed'
1154 DEPLOYDONE = 'deploy complete'
1155 DELETING = 'deleting'
1156 DELETED = 'deleted'
1157 ERROR = 'error'
1158
1159
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001160class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001161
1162 credentials = ['primary', 'admin']
1163
Adam Gandelman4a48a602014-03-20 18:23:18 -07001164 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001165 def skip_checks(cls):
1166 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001167 if (not CONF.service_available.ironic or
1168 not CONF.baremetal.driver_enabled):
1169 msg = 'Ironic not available or Ironic compute driver not enabled'
1170 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001171
1172 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001173 def setup_clients(cls):
1174 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001175
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001176 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001177
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001178 @classmethod
1179 def resource_setup(cls):
1180 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001181 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001182 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001183
1184 def _node_state_timeout(self, node_id, state_attr,
1185 target_states, timeout=10, interval=1):
1186 if not isinstance(target_states, list):
1187 target_states = [target_states]
1188
1189 def check_state():
1190 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001191 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001192 return True
1193 return False
1194
1195 if not tempest.test.call_until_true(
1196 check_state, timeout, interval):
1197 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1198 (node_id, state_attr, target_states))
1199 raise exceptions.TimeoutException(msg)
1200
1201 def wait_provisioning_state(self, node_id, state, timeout):
1202 self._node_state_timeout(
1203 node_id=node_id, state_attr='provision_state',
1204 target_states=state, timeout=timeout)
1205
1206 def wait_power_state(self, node_id, state):
1207 self._node_state_timeout(
1208 node_id=node_id, state_attr='power_state',
1209 target_states=state, timeout=CONF.baremetal.power_timeout)
1210
1211 def wait_node(self, instance_id):
1212 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001213
Adam Gandelman4a48a602014-03-20 18:23:18 -07001214 def _get_node():
1215 node = None
1216 try:
1217 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001218 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001219 pass
1220 return node is not None
1221
1222 if not tempest.test.call_until_true(
1223 _get_node, CONF.baremetal.association_timeout, 1):
1224 msg = ('Timed out waiting to get Ironic node by instance id %s'
1225 % instance_id)
1226 raise exceptions.TimeoutException(msg)
1227
1228 def get_node(self, node_id=None, instance_id=None):
1229 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001230 _, body = self.baremetal_client.show_node(node_id)
1231 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001232 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001233 _, body = self.baremetal_client.show_node_by_instance_uuid(
1234 instance_id)
1235 if body['nodes']:
1236 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001237
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001238 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001239 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001240 _, body = self.baremetal_client.list_node_ports(node_uuid)
1241 for port in body['ports']:
1242 _, p = self.baremetal_client.show_port(port['uuid'])
1243 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001244 return ports
1245
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001246 def add_keypair(self):
1247 self.keypair = self.create_keypair()
1248
1249 def verify_connectivity(self, ip=None):
1250 if ip:
1251 dest = self.get_remote_client(ip)
1252 else:
1253 dest = self.get_remote_client(self.instance)
1254 dest.validate_authentication()
1255
1256 def boot_instance(self):
1257 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001258 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001259 }
1260 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001261 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001262
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001263 self.wait_node(self.instance['id'])
1264 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001265
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001266 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001267
1268 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001269 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001270 [BaremetalProvisionStates.DEPLOYWAIT,
1271 BaremetalProvisionStates.ACTIVE],
1272 timeout=15)
1273
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001274 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001275 BaremetalProvisionStates.ACTIVE,
1276 timeout=CONF.baremetal.active_timeout)
1277
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001278 waiters.wait_for_server_status(self.servers_client,
1279 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001280 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001281 self.instance = (self.servers_client.show_server(self.instance['id'])
1282 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001283
1284 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001285 self.servers_client.delete_server(self.instance['id'])
1286 self.wait_power_state(self.node['uuid'],
1287 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001288 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001289 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001290 BaremetalProvisionStates.NOSTATE,
1291 timeout=CONF.baremetal.unprovision_timeout)
1292
Adam Gandelman4a48a602014-03-20 18:23:18 -07001293
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001294class EncryptionScenarioTest(ScenarioTest):
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001295 """
1296 Base class for encryption scenario tests
1297 """
1298
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001299 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001300
1301 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001302 def setup_clients(cls):
1303 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001304 if CONF.volume_feature_enabled.api_v1:
1305 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1306 else:
1307 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001308
1309 def _wait_for_volume_status(self, status):
1310 self.status_timeout(
1311 self.volume_client.volumes, self.volume.id, status)
1312
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001313 def nova_boot(self):
1314 self.keypair = self.create_keypair()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001315 create_kwargs = {'key_name': self.keypair['name']}
1316 self.server = self.create_server(image=self.image,
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001317 create_kwargs=create_kwargs)
1318
1319 def create_volume_type(self, client=None, name=None):
1320 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001321 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001322 if not name:
1323 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001324 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001325 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001326 body = client.create_volume_type(
John Warrend053ded2015-08-13 15:22:48 +00001327 randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001328 self.assertIn('id', body)
1329 self.addCleanup(client.delete_volume_type, body['id'])
1330 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001331
1332 def create_encryption_type(self, client=None, type_id=None, provider=None,
1333 key_size=None, cipher=None,
1334 control_location=None):
1335 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001336 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001337 if not type_id:
1338 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001339 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001340 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001341 client.create_encryption_type(
1342 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001343 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001344
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001345
Masayuki Igawa0870db52015-09-18 21:08:36 +09001346class ObjectStorageScenarioTest(ScenarioTest):
Chris Dent0d494112014-08-26 13:48:30 +01001347 """
Masayuki Igawa0870db52015-09-18 21:08:36 +09001348 Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001349
1350 Subclasses implement the tests that use the methods provided by this
1351 class.
1352 """
1353
1354 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001355 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001356 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001357 if not CONF.service_available.swift:
1358 skip_msg = ("%s skipped as swift is not available" %
1359 cls.__name__)
1360 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001361
1362 @classmethod
1363 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001364 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001365 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001366 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001367 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001368
1369 @classmethod
1370 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001371 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001372 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001373 cls.account_client = cls.os_operator.account_client
1374 cls.container_client = cls.os_operator.container_client
1375 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001376
Chris Dentde456a12014-09-10 12:41:15 +01001377 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001378 """get swift status for our user account."""
1379 self.account_client.list_account_containers()
1380 LOG.debug('Swift status information obtained successfully')
1381
Chris Dentde456a12014-09-10 12:41:15 +01001382 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001383 name = container_name or data_utils.rand_name(
1384 'swift-scenario-container')
1385 self.container_client.create_container(name)
1386 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001387 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001388 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001389 self.addCleanup(self.delete_wrapper,
1390 self.container_client.delete_container,
1391 name)
Chris Dent0d494112014-08-26 13:48:30 +01001392 return name
1393
Chris Dentde456a12014-09-10 12:41:15 +01001394 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001395 self.container_client.delete_container(container_name)
1396 LOG.debug('Container %s deleted' % (container_name))
1397
Chris Dentde456a12014-09-10 12:41:15 +01001398 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001399 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1400 obj_data = data_utils.arbitrary_string()
1401 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001402 self.addCleanup(self.delete_wrapper,
1403 self.object_client.delete_object,
1404 container_name,
1405 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001406 return obj_name, obj_data
1407
Chris Dentde456a12014-09-10 12:41:15 +01001408 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001409 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001410 self.list_and_check_container_objects(container_name,
1411 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001412
Chris Dentde456a12014-09-10 12:41:15 +01001413 def list_and_check_container_objects(self, container_name,
1414 present_obj=None,
1415 not_present_obj=None):
Chris Dent0d494112014-08-26 13:48:30 +01001416 """
1417 List objects for a given container and assert which are present and
1418 which are not.
1419 """
Ghanshyam2a180b82014-06-16 13:54:22 +09001420 if present_obj is None:
1421 present_obj = []
1422 if not_present_obj is None:
1423 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001424 _, object_list = self.container_client.list_container_contents(
1425 container_name)
1426 if present_obj:
1427 for obj in present_obj:
1428 self.assertIn(obj, object_list)
1429 if not_present_obj:
1430 for obj in not_present_obj:
1431 self.assertNotIn(obj, object_list)
1432
Chris Dentde456a12014-09-10 12:41:15 +01001433 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001434 metadata_param = {'metadata_prefix': 'x-container-',
1435 'metadata': {'read': acl}}
1436 self.container_client.update_container_metadata(container_name,
1437 **metadata_param)
1438 resp, _ = self.container_client.list_container_metadata(container_name)
1439 self.assertEqual(resp['x-container-read'], acl)
1440
Chris Dentde456a12014-09-10 12:41:15 +01001441 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001442 _, obj = self.object_client.get_object(container_name, obj_name)
1443 self.assertEqual(obj, expected_data)