blob: 6548d2895ed1ba68b906ab57863d1a957ba30bf8 [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
John Warren94d8faf2015-09-15 12:22:24 -040064 cls.networks_client = cls.manager.networks_client
John Warren49c0fe52015-10-22 12:35:54 -040065 cls.ports_client = cls.manager.ports_client
John Warren3961acd2015-10-02 14:38:53 -040066 cls.subnets_client = cls.manager.subnets_client
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090067 # Heat client
68 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010069
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030070 if CONF.volume_feature_enabled.api_v1:
71 cls.volumes_client = cls.manager.volumes_client
72 cls.snapshots_client = cls.manager.snapshots_client
73 else:
74 cls.volumes_client = cls.manager.volumes_v2_client
75 cls.snapshots_client = cls.manager.snapshots_v2_client
76
Andrea Frittoli247058f2014-07-16 16:09:22 +010077 # ## Methods to handle sync and async deletes
78
79 def setUp(self):
80 super(ScenarioTest, self).setUp()
81 self.cleanup_waits = []
82 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
83 # because scenario tests in the same test class should not share
84 # resources. If resources were shared between test cases then it
85 # should be a single scenario test instead of multiples.
86
87 # NOTE(yfried): this list is cleaned at the end of test_methods and
88 # not at the end of the class
89 self.addCleanup(self._wait_for_cleanups)
90
Yair Fried1fc32a12014-08-04 09:11:30 +030091 def delete_wrapper(self, delete_thing, *args, **kwargs):
Andrea Frittoli247058f2014-07-16 16:09:22 +010092 """Ignores NotFound exceptions for delete operations.
93
Yair Fried1fc32a12014-08-04 09:11:30 +030094 @param delete_thing: delete method of a resource. method will be
95 executed as delete_thing(*args, **kwargs)
96
Andrea Frittoli247058f2014-07-16 16:09:22 +010097 """
98 try:
99 # Tempest clients return dicts, so there is no common delete
100 # method available. Using a callable instead
Yair Fried1fc32a12014-08-04 09:11:30 +0300101 delete_thing(*args, **kwargs)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900102 except lib_exc.NotFound:
Andrea Frittoli247058f2014-07-16 16:09:22 +0100103 # If the resource is already missing, mission accomplished.
104 pass
105
106 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +0900107 cleanup_callable, cleanup_args=None,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000108 cleanup_kwargs=None, waiter_client=None):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700109 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100110
111 @param waiter_callable: callable to wait for the resource to delete
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000112 with the following waiter_client if specified.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100113 @param thing_id: the id of the resource to be cleaned-up
114 @param thing_id_param: the name of the id param in the waiter
115 @param cleanup_callable: method to load pass to self.addCleanup with
116 the following *cleanup_args, **cleanup_kwargs.
117 usually a delete method.
118 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900119 if cleanup_args is None:
120 cleanup_args = []
121 if cleanup_kwargs is None:
122 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100123 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
124 wait_dict = {
125 'waiter_callable': waiter_callable,
126 thing_id_param: thing_id
127 }
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000128 if waiter_client:
129 wait_dict['client'] = waiter_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100130 self.cleanup_waits.append(wait_dict)
131
132 def _wait_for_cleanups(self):
133 """To handle async delete actions, a list of waits is added
134 which will be iterated over as the last step of clearing the
135 cleanup queue. That way all the delete calls are made up front
136 and the tests won't succeed unless the deletes are eventually
137 successful. This is the same basic approach used in the api tests to
138 limit cleanup execution time except here it is multi-resource,
139 because of the nature of the scenario tests.
140 """
141 for wait in self.cleanup_waits:
142 waiter_callable = wait.pop('waiter_callable')
143 waiter_callable(**wait)
144
145 # ## Test functions library
146 #
147 # The create_[resource] functions only return body and discard the
148 # resp part which is not used in scenario tests
149
Yair Frieddb6c9e92014-08-06 08:53:13 +0300150 def create_keypair(self, client=None):
151 if not client:
152 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100153 name = data_utils.rand_name(self.__class__.__name__)
154 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000155 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300156 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900157 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100158
159 def create_server(self, name=None, image=None, flavor=None,
160 wait_on_boot=True, wait_on_delete=True,
Ghanshyam2a180b82014-06-16 13:54:22 +0900161 create_kwargs=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100162 """Creates VM instance.
163
164 @param image: image from which to create the instance
165 @param wait_on_boot: wait for status ACTIVE before continue
166 @param wait_on_delete: force synchronous delete on cleanup
167 @param create_kwargs: additional details for instance creation
168 @return: server dict
169 """
170 if name is None:
171 name = data_utils.rand_name(self.__class__.__name__)
172 if image is None:
173 image = CONF.compute.image_ref
174 if flavor is None:
175 flavor = CONF.compute.flavor_ref
Ghanshyam2a180b82014-06-16 13:54:22 +0900176 if create_kwargs is None:
177 create_kwargs = {}
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530178 network = self.get_tenant_network()
Matthew Treinish4bbc1992015-04-07 11:13:40 -0400179 create_kwargs = fixed_network.set_networks_kwarg(network,
180 create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100181
Andrea Frittoli247058f2014-07-16 16:09:22 +0100182 LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
183 name, image, flavor)
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +0000184 server = self.servers_client.create_server(name=name, imageRef=image,
185 flavorRef=flavor,
ghanshyam0f825252015-08-25 16:02:50 +0900186 **create_kwargs)['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100187 if wait_on_delete:
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000188 self.addCleanup(waiters.wait_for_server_termination,
189 self.servers_client,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100190 server['id'])
191 self.addCleanup_with_wait(
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000192 waiter_callable=waiters.wait_for_server_termination,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100193 thing_id=server['id'], thing_id_param='server_id',
194 cleanup_callable=self.delete_wrapper,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000195 cleanup_args=[self.servers_client.delete_server, server['id']],
196 waiter_client=self.servers_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100197 if wait_on_boot:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000198 waiters.wait_for_server_status(self.servers_client,
199 server_id=server['id'],
200 status='ACTIVE')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100201 # The instance retrieved on creation is missing network
202 # details, necessitating retrieval after it becomes active to
203 # ensure correct details.
ghanshyam0f825252015-08-25 16:02:50 +0900204 server = self.servers_client.show_server(server['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100205 self.assertEqual(server['name'], name)
206 return server
207
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100208 def create_volume(self, size=None, name=None, snapshot_id=None,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100209 imageRef=None, volume_type=None, wait_on_delete=True):
210 if name is None:
211 name = data_utils.rand_name(self.__class__.__name__)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000212 volume = self.volumes_client.create_volume(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100213 size=size, display_name=name, snapshot_id=snapshot_id,
John Warren6177c9e2015-08-19 20:00:17 +0000214 imageRef=imageRef, volume_type=volume_type)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700215
Andrea Frittoli247058f2014-07-16 16:09:22 +0100216 if wait_on_delete:
217 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
218 volume['id'])
Matt Riedemanne85c2702014-09-10 11:50:13 -0700219 self.addCleanup(self.delete_wrapper,
220 self.volumes_client.delete_volume, volume['id'])
221 else:
222 self.addCleanup_with_wait(
223 waiter_callable=self.volumes_client.wait_for_resource_deletion,
224 thing_id=volume['id'], thing_id_param='id',
225 cleanup_callable=self.delete_wrapper,
226 cleanup_args=[self.volumes_client.delete_volume, volume['id']])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100227
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300228 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
229 if 'display_name' in volume:
230 self.assertEqual(name, volume['display_name'])
231 else:
232 self.assertEqual(name, volume['name'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100233 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
234 # The volume retrieved on creation has a non-up-to-date status.
235 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000236 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100237 return volume
238
Yair Fried1fc32a12014-08-04 09:11:30 +0300239 def _create_loginable_secgroup_rule(self, secgroup_id=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100240 _client = self.security_groups_client
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000241 _client_rules = self.security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100242 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900243 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100244 for sg in sgs:
245 if sg['name'] == 'default':
246 secgroup_id = sg['id']
247
248 # These rules are intended to permit inbound ssh and icmp
249 # traffic from all sources, so no group_id is provided.
250 # Setting a group_id would only permit traffic from ports
251 # belonging to the same security group.
252 rulesets = [
253 {
254 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000255 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100256 'from_port': 22,
257 'to_port': 22,
258 'cidr': '0.0.0.0/0',
259 },
260 {
261 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000262 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100263 'from_port': -1,
264 'to_port': -1,
265 'cidr': '0.0.0.0/0',
266 }
267 ]
268 rules = list()
269 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000270 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900271 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100272 self.addCleanup(self.delete_wrapper,
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000273 _client_rules.delete_security_group_rule,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100274 sg_rule['id'])
275 rules.append(sg_rule)
276 return rules
277
Yair Fried1fc32a12014-08-04 09:11:30 +0300278 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100279 # Create security group
280 sg_name = data_utils.rand_name(self.__class__.__name__)
281 sg_desc = sg_name + " description"
David Kranz9964b4e2015-02-06 15:45:29 -0500282 secgroup = self.security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900283 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100284 self.assertEqual(secgroup['name'], sg_name)
285 self.assertEqual(secgroup['description'], sg_desc)
286 self.addCleanup(self.delete_wrapper,
287 self.security_groups_client.delete_security_group,
288 secgroup['id'])
289
290 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300291 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100292
293 return secgroup
294
JordanP3fe2dc32014-11-17 13:06:01 +0100295 def get_remote_client(self, server_or_ip, username=None, private_key=None,
296 log_console_of_servers=None):
297 """Get a SSH client to a remote server
298
299 @param server_or_ip a server object as returned by Tempest compute
300 client or an IP address to connect to
301 @param username name of the Linux account on the remote server
302 @param private_key the SSH private key to use
303 @param log_console_of_servers a list of server objects. Each server
304 in the list will have its console printed in the logs in case the
305 SSH connection failed to be established
306 @return a RemoteClient object
307 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100308 if isinstance(server_or_ip, six.string_types):
309 ip = server_or_ip
310 else:
Andrew Boik4a3daf12015-03-27 01:59:31 -0400311 addrs = server_or_ip['addresses'][CONF.compute.network_for_ssh]
312 try:
313 ip = (addr['addr'] for addr in addrs if
314 netaddr.valid_ipv4(addr['addr'])).next()
315 except StopIteration:
316 raise lib_exc.NotFound("No IPv4 addresses to use for SSH to "
317 "remote server.")
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700318
Andrea Frittoli247058f2014-07-16 16:09:22 +0100319 if username is None:
320 username = CONF.scenario.ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800321 # Set this with 'keypair' or others to log in with keypair or
322 # username/password.
323 if CONF.compute.ssh_auth_method == 'keypair':
324 password = None
325 if private_key is None:
326 private_key = self.keypair['private_key']
327 else:
328 password = CONF.compute.image_ssh_password
329 private_key = None
Andrea Frittoli247058f2014-07-16 16:09:22 +0100330 linux_client = remote_client.RemoteClient(ip, username,
wantwatering896300c2015-03-27 15:17:42 +0800331 pkey=private_key,
332 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100333 try:
334 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700335 except Exception as e:
336 message = ('Initializing SSH connection to %(ip)s failed. '
337 'Error: %(error)s' % {'ip': ip, 'error': e})
338 caller = misc_utils.find_test_caller()
339 if caller:
340 message = '(%s) %s' % (caller, message)
341 LOG.exception(message)
Marc Kodererb06db502015-04-30 09:31:27 +0200342 # If we don't explicitly set for which servers we want to
JordanP3fe2dc32014-11-17 13:06:01 +0100343 # log the console output then all the servers will be logged.
344 # See the definition of _log_console_output()
345 self._log_console_output(log_console_of_servers)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100346 raise
347
348 return linux_client
349
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000350 def _image_create(self, name, fmt, path,
351 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900352 if properties is None:
353 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100354 name = data_utils.rand_name('%s-' % name)
355 image_file = open(path, 'rb')
356 self.addCleanup(image_file.close)
357 params = {
358 'name': name,
359 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000360 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100361 'is_public': 'False',
362 }
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000363 params['properties'] = properties
John Warren66207252015-07-31 15:51:02 -0400364 image = self.image_client.create_image(**params)['image']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100365 self.addCleanup(self.image_client.delete_image, image['id'])
366 self.assertEqual("queued", image['status'])
367 self.image_client.update_image(image['id'], data=image_file)
368 return image['id']
369
370 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300371 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100372 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
373 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
374 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300375 img_container_format = CONF.scenario.img_container_format
376 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000377 img_properties = CONF.scenario.img_properties
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300378 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000379 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300380 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000381 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100382 try:
383 self.image = self._image_create('scenario-img',
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300384 img_container_format,
385 img_path,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000386 disk_format=img_disk_format,
387 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100388 except IOError:
389 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
390 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
391 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000392 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100393 self.image = self._image_create('scenario-ami', 'ami',
394 path=ami_img_path,
395 properties=properties)
396 LOG.debug("image:%s" % self.image)
397
398 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400399 if not CONF.compute_feature_enabled.console_output:
400 LOG.debug('Console output not supported, cannot log')
401 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100402 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500403 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100404 servers = servers['servers']
405 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500406 console_output = self.servers_client.get_console_output(
ghanshyam0f825252015-08-25 16:02:50 +0900407 server['id'], length=None)['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500408 LOG.debug('Console output for %s\nbody=\n%s',
409 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100410
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000411 def _log_net_info(self, exc):
412 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300413 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000414 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000415
nithya-ganesan882595e2014-07-29 18:51:07 +0000416 def create_server_snapshot(self, server, name=None):
417 # Glance client
418 _image_client = self.image_client
419 # Compute client
420 _images_client = self.images_client
421 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000422 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000423 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000424 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500425 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000426 _image_client.wait_for_image_status(image_id, 'active')
427 self.addCleanup_with_wait(
428 waiter_callable=_image_client.wait_for_resource_deletion,
429 thing_id=image_id, thing_id_param='id',
430 cleanup_callable=self.delete_wrapper,
431 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500432 snapshot_image = _image_client.get_image_meta(image_id)
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300433
434 bdm = snapshot_image.get('properties', {}).get('block_device_mapping')
435 if bdm:
436 bdm = json.loads(bdm)
437 if bdm and 'snapshot_id' in bdm[0]:
438 snapshot_id = bdm[0]['snapshot_id']
439 self.addCleanup(
440 self.snapshots_client.wait_for_resource_deletion,
441 snapshot_id)
442 self.addCleanup(
443 self.delete_wrapper, self.snapshots_client.delete_snapshot,
444 snapshot_id)
Andrey Pavlovd35957b2015-08-27 20:12:15 +0300445 self.snapshots_client.wait_for_snapshot_status(snapshot_id,
446 'available')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300447
nithya-ganesan882595e2014-07-29 18:51:07 +0000448 image_name = snapshot_image['name']
449 self.assertEqual(name, image_name)
450 LOG.debug("Created snapshot image %s for server %s",
451 image_name, server['name'])
452 return snapshot_image
453
Jordan Pittier7cf64762015-10-14 15:01:12 +0200454 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000455 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200456 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900457 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200458 self.assertEqual(volume_to_attach['id'], volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900459 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900460
Jordan Pittier7cf64762015-10-14 15:01:12 +0200461 # Return the updated volume after the attachment
462 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900463
Jordan Pittier7cf64762015-10-14 15:01:12 +0200464 def nova_volume_detach(self, server, volume):
465 self.servers_client.detach_volume(server['id'], volume['id'])
466 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
467
468 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900469 self.assertEqual('available', volume['status'])
470
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700471 def rebuild_server(self, server_id, image=None,
472 preserve_ephemeral=False, wait=True,
473 rebuild_kwargs=None):
474 if image is None:
475 image = CONF.compute.image_ref
476
477 rebuild_kwargs = rebuild_kwargs or {}
478
479 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
480 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000481 self.servers_client.rebuild_server(
482 server_id=server_id, image_ref=image,
483 preserve_ephemeral=preserve_ephemeral,
484 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700485 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000486 waiters.wait_for_server_status(self.servers_client,
487 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700488
Steven Hardyda2a8352014-10-02 12:52:20 +0100489 def ping_ip_address(self, ip_address, should_succeed=True,
490 ping_timeout=None):
491 timeout = ping_timeout or CONF.compute.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700492 cmd = ['ping', '-c1', '-w1', ip_address]
493
494 def ping():
495 proc = subprocess.Popen(cmd,
496 stdout=subprocess.PIPE,
497 stderr=subprocess.PIPE)
498 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000499
Aaron Rosena7df13b2014-09-23 09:45:45 -0700500 return (proc.returncode == 0) == should_succeed
501
Shuquan Huang753629e2015-07-20 08:52:29 +0000502 caller = misc_utils.find_test_caller()
503 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
504 ' expected result is %(should_succeed)s' % {
505 'caller': caller, 'ip': ip_address, 'timeout': timeout,
506 'should_succeed':
507 'reachable' if should_succeed else 'unreachable'
508 })
509 result = tempest.test.call_until_true(ping, timeout, 1)
510 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
511 'ping result is %(result)s' % {
512 'caller': caller, 'ip': ip_address, 'timeout': timeout,
513 'result': 'expected' if result else 'unexpected'
514 })
515 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700516
Yair Friedae0e73d2014-11-24 11:56:26 +0200517 def check_vm_connectivity(self, ip_address,
518 username=None,
519 private_key=None,
520 should_connect=True):
521 """
522 :param ip_address: server to test against
523 :param username: server's ssh username
524 :param private_key: server's ssh private key to be used
525 :param should_connect: True/False indicates positive/negative test
526 positive - attempt ping and ssh
527 negative - attempt ping and fail if succeed
528
529 :raises: AssertError if the result of the connectivity check does
530 not match the value of the should_connect param
531 """
532 if should_connect:
533 msg = "Timed out waiting for %s to become reachable" % ip_address
534 else:
535 msg = "ip address %s is reachable" % ip_address
536 self.assertTrue(self.ping_ip_address(ip_address,
537 should_succeed=should_connect),
538 msg=msg)
539 if should_connect:
540 # no need to check ssh for negative connectivity
541 self.get_remote_client(ip_address, username, private_key)
542
543 def check_public_network_connectivity(self, ip_address, username,
544 private_key, should_connect=True,
545 msg=None, servers=None):
546 # The target login is assumed to have been configured for
547 # key-based authentication by cloud-init.
548 LOG.debug('checking network connections to IP %s with user: %s' %
549 (ip_address, username))
550 try:
551 self.check_vm_connectivity(ip_address,
552 username,
553 private_key,
554 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500555 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200556 ex_msg = 'Public network connectivity check failed'
557 if msg:
558 ex_msg += ": " + msg
559 LOG.exception(ex_msg)
560 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200561 raise
562
563 def create_floating_ip(self, thing, pool_name=None):
564 """Creates a floating IP and associates to a server using
565 Nova clients
566 """
567
ghanshyam9a3a9a22015-08-18 17:03:55 +0900568 floating_ip = (self.floating_ips_client.create_floating_ip(pool_name)
569 ['floating_ip'])
Yair Friedae0e73d2014-11-24 11:56:26 +0200570 self.addCleanup(self.delete_wrapper,
571 self.floating_ips_client.delete_floating_ip,
572 floating_ip['id'])
573 self.floating_ips_client.associate_floating_ip_to_server(
574 floating_ip['ip'], thing['id'])
575 return floating_ip
576
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700577 def create_timestamp(self, server_or_ip, dev_name=None, mount_path='/mnt',
578 private_key=None):
579 ssh_client = self.get_remote_client(server_or_ip,
580 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300581 if dev_name is not None:
582 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700583 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300584 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
585 ssh_client.exec_command(cmd_timestamp)
586 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
587 % mount_path)
588 if dev_name is not None:
589 ssh_client.umount(mount_path)
590 return timestamp
591
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700592 def get_timestamp(self, server_or_ip, dev_name=None, mount_path='/mnt',
593 private_key=None):
594 ssh_client = self.get_remote_client(server_or_ip,
595 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300596 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700597 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300598 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
599 % mount_path)
600 if dev_name is not None:
601 ssh_client.umount(mount_path)
602 return timestamp
603
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100604
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100605class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300606 """Base class for network scenario tests.
607 This class provide helpers for network scenario tests, using the neutron
608 API. Helpers from ancestor which use the nova network API are overridden
609 with the neutron API.
610
611 This Class also enforces using Neutron instead of novanetwork.
612 Subclassed tests will be skipped if Neutron is not enabled
613
614 """
615
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000616 credentials = ['primary', 'admin']
617
Yair Fried1fc32a12014-08-04 09:11:30 +0300618 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000619 def skip_checks(cls):
620 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100621 if not CONF.service_available.neutron:
622 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300623
624 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100625 def resource_setup(cls):
626 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300627 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300628
John Warren94d8faf2015-09-15 12:22:24 -0400629 def _create_network(self, client=None, networks_client=None,
630 tenant_id=None, namestart='network-smoke-'):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300631 if not client:
632 client = self.network_client
John Warren94d8faf2015-09-15 12:22:24 -0400633 if not networks_client:
634 networks_client = self.networks_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300635 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000636 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300637 name = data_utils.rand_name(namestart)
John Warren94d8faf2015-09-15 12:22:24 -0400638 result = networks_client.create_network(name=name, tenant_id=tenant_id)
639 network = net_resources.DeletableNetwork(
640 networks_client=networks_client, **result['network'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300641 self.assertEqual(network.name, name)
642 self.addCleanup(self.delete_wrapper, network.delete)
643 return network
644
645 def _list_networks(self, *args, **kwargs):
646 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400647 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900648 *args, **kwargs)
649 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300650
651 def _list_subnets(self, *args, **kwargs):
652 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400653 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900654 *args, **kwargs)
655 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300656
657 def _list_routers(self, *args, **kwargs):
658 """List routers using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900659 routers_list = self.admin_manager.network_client.list_routers(
660 *args, **kwargs)
661 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300662
663 def _list_ports(self, *args, **kwargs):
664 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400665 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900666 *args, **kwargs)
667 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300668
Yair Fried564d89d2015-08-06 17:02:12 +0300669 def _list_agents(self, *args, **kwargs):
670 """List agents using admin creds """
671 agents_list = self.admin_manager.network_client.list_agents(
672 *args, **kwargs)
673 return agents_list['agents']
674
John Warren3961acd2015-10-02 14:38:53 -0400675 def _create_subnet(self, network, client=None, subnets_client=None,
676 namestart='subnet-smoke', **kwargs):
Yair Fried1fc32a12014-08-04 09:11:30 +0300677 """
678 Create a subnet for the given network within the cidr block
679 configured for tenant networks.
680 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300681 if not client:
682 client = self.network_client
John Warren3961acd2015-10-02 14:38:53 -0400683 if not subnets_client:
684 subnets_client = self.subnets_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300685
686 def cidr_in_use(cidr, tenant_id):
687 """
688 :return True if subnet with cidr already exist in tenant
689 False else
690 """
691 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
692 return len(cidr_in_use) != 0
693
Kirill Shileev14113572014-11-21 16:58:02 +0300694 ip_version = kwargs.pop('ip_version', 4)
695
696 if ip_version == 6:
697 tenant_cidr = netaddr.IPNetwork(
698 CONF.network.tenant_network_v6_cidr)
699 num_bits = CONF.network.tenant_network_v6_mask_bits
700 else:
701 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
702 num_bits = CONF.network.tenant_network_mask_bits
703
Yair Fried1fc32a12014-08-04 09:11:30 +0300704 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300705 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300706 # Repeatedly attempt subnet creation with sequential cidr
707 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300708 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300709 str_cidr = str(subnet_cidr)
710 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
711 continue
712
713 subnet = dict(
714 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300715 network_id=network.id,
716 tenant_id=network.tenant_id,
717 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300718 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300719 **kwargs
720 )
721 try:
John Warren3961acd2015-10-02 14:38:53 -0400722 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300723 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900724 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300725 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
726 if not is_overlapping_cidr:
727 raise
728 self.assertIsNotNone(result, 'Unable to allocate tenant network')
John Warren3961acd2015-10-02 14:38:53 -0400729 subnet = net_resources.DeletableSubnet(
730 network_client=client, subnets_client=subnets_client,
731 **result['subnet'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300732 self.assertEqual(subnet.cidr, str_cidr)
733 self.addCleanup(self.delete_wrapper, subnet.delete)
734 return subnet
735
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200736 def _create_port(self, network_id, client=None, namestart='port-quotatest',
737 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300738 if not client:
John Warren49c0fe52015-10-22 12:35:54 -0400739 client = self.ports_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300740 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500741 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300742 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200743 network_id=network_id,
744 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300745 self.assertIsNotNone(result, 'Unable to allocate port')
John Warren49c0fe52015-10-22 12:35:54 -0400746 port = net_resources.DeletablePort(ports_client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300747 **result['port'])
748 self.addCleanup(self.delete_wrapper, port.delete)
749 return port
750
Kirill Shileev14113572014-11-21 16:58:02 +0300751 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Ken'ichi Ohmichi30b769e2015-10-14 09:47:22 +0000752 ports = self._list_ports(device_id=server['id'], status='ACTIVE',
Yair Fried1fc32a12014-08-04 09:11:30 +0300753 fixed_ip=ip_addr)
Kirill Shileev14113572014-11-21 16:58:02 +0300754 # it might happen here that this port has more then one ip address
755 # as in case of dual stack- when this port is created on 2 subnets
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200756 port_map = [(p["id"], fxip["ip_address"])
757 for p in ports
758 for fxip in p["fixed_ips"]
759 if netaddr.valid_ipv4(fxip["ip_address"])]
760
John L. Villalovosb83286f2015-11-04 14:46:57 -0800761 self.assertNotEqual(0, len(port_map),
762 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200763 self.assertEqual(len(port_map), 1,
764 "Found multiple IPv4 addresses: %s. "
765 "Unable to determine which port to target."
766 % port_map)
767 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300768
David Shrewsbury9bac3662014-08-07 15:07:01 -0400769 def _get_network_by_name(self, network_name):
770 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700771 self.assertNotEqual(len(net), 0,
772 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300773 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400774
Yair Friedae0e73d2014-11-24 11:56:26 +0200775 def create_floating_ip(self, thing, external_network_id=None,
776 port_id=None, client=None):
777 """Creates a floating IP and associates to a resource/port using
778 Neutron client
779 """
780 if not external_network_id:
781 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300782 if not client:
783 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300784 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300785 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
786 else:
787 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500788 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300789 floating_network_id=external_network_id,
790 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300791 tenant_id=thing['tenant_id'],
792 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300793 )
794 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300795 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300796 **result['floatingip'])
797 self.addCleanup(self.delete_wrapper, floating_ip.delete)
798 return floating_ip
799
800 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300801 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300802 floating_ip.update(port_id=port_id)
803 self.assertEqual(port_id, floating_ip.port_id)
804 return floating_ip
805
806 def _disassociate_floating_ip(self, floating_ip):
807 """
808 :param floating_ip: type DeletableFloatingIp
809 """
810 floating_ip.update(port_id=None)
811 self.assertIsNone(floating_ip.port_id)
812 return floating_ip
813
Yair Fried45f92952014-06-26 05:19:19 +0300814 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000815 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300816
817 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
818 to check status
819 :param status: target status
820 :raises: AssertionError if status doesn't match
821 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000822 def refresh():
823 floating_ip.refresh()
824 return status == floating_ip.status
825
826 tempest.test.call_until_true(refresh,
827 CONF.network.build_timeout,
828 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300829 self.assertEqual(status, floating_ip.status,
830 message="FloatingIP: {fp} is at status: {cst}. "
831 "failed to reach status: {st}"
832 .format(fp=floating_ip, cst=floating_ip.status,
833 st=status))
834 LOG.info("FloatingIP: {fp} is at status: {st}"
835 .format(fp=floating_ip, st=status))
836
Yair Fried1fc32a12014-08-04 09:11:30 +0300837 def _check_tenant_network_connectivity(self, server,
838 username,
839 private_key,
840 should_connect=True,
841 servers_for_debug=None):
842 if not CONF.network.tenant_networks_reachable:
843 msg = 'Tenant networks not configured to be reachable.'
844 LOG.info(msg)
845 return
846 # The target login is assumed to have been configured for
847 # key-based authentication by cloud-init.
848 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400849 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300850 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900851 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200852 username,
853 private_key,
854 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300855 except Exception as e:
856 LOG.exception('Tenant network connectivity check failed')
857 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000858 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300859 raise
860
861 def _check_remote_connectivity(self, source, dest, should_succeed=True):
862 """
863 check ping server via source ssh connection
864
865 :param source: RemoteClient: an ssh connection from which to ping
866 :param dest: and IP to ping against
867 :param should_succeed: boolean should ping succeed or not
868 :returns: boolean -- should_succeed == ping
869 :returns: ping is false if ping failed
870 """
871 def ping_remote():
872 try:
873 source.ping_host(dest)
Andrey Pavlov64723762015-04-29 06:24:58 +0300874 except lib_exc.SSHExecCommandFailed:
Yair Fried1fc32a12014-08-04 09:11:30 +0300875 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
876 % (dest, source.ssh_client.host))
877 return not should_succeed
878 return should_succeed
879
880 return tempest.test.call_until_true(ping_remote,
881 CONF.compute.ping_timeout,
882 1)
883
Yair Frieddb6c9e92014-08-06 08:53:13 +0300884 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300885 namestart='secgroup-smoke'):
886 if client is None:
887 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300888 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000889 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300890 secgroup = self._create_empty_security_group(namestart=namestart,
891 client=client,
892 tenant_id=tenant_id)
893
894 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900895 rules = self._create_loginable_secgroup_rule(client=client,
896 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300897 for rule in rules:
898 self.assertEqual(tenant_id, rule.tenant_id)
899 self.assertEqual(secgroup.id, rule.security_group_id)
900 return secgroup
901
Yair Frieddb6c9e92014-08-06 08:53:13 +0300902 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300903 namestart='secgroup-smoke'):
904 """Create a security group without rules.
905
906 Default rules will be created:
907 - IPv4 egress to any
908 - IPv6 egress to any
909
910 :param tenant_id: secgroup will be created in this tenant
911 :returns: DeletableSecurityGroup -- containing the secgroup created
912 """
913 if client is None:
914 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300915 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000916 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300917 sg_name = data_utils.rand_name(namestart)
918 sg_desc = sg_name + " description"
919 sg_dict = dict(name=sg_name,
920 description=sg_desc)
921 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500922 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300923 secgroup = net_resources.DeletableSecurityGroup(
924 client=client,
925 **result['security_group']
926 )
927 self.assertEqual(secgroup.name, sg_name)
928 self.assertEqual(tenant_id, secgroup.tenant_id)
929 self.assertEqual(secgroup.description, sg_desc)
930 self.addCleanup(self.delete_wrapper, secgroup.delete)
931 return secgroup
932
Yair Frieddb6c9e92014-08-06 08:53:13 +0300933 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300934 """Get default secgroup for given tenant_id.
935
936 :returns: DeletableSecurityGroup -- default secgroup for given tenant
937 """
938 if client is None:
939 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300940 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000941 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300942 sgs = [
943 sg for sg in client.list_security_groups().values()[0]
944 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
945 ]
946 msg = "No default security group for tenant %s." % (tenant_id)
947 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300948 return net_resources.DeletableSecurityGroup(client=client,
949 **sgs[0])
950
Yair Frieddb6c9e92014-08-06 08:53:13 +0300951 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300952 tenant_id=None, **kwargs):
953 """Create a rule from a dictionary of rule parameters.
954
955 Create a rule in a secgroup. if secgroup not defined will search for
956 default secgroup in tenant_id.
957
958 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300959 :param tenant_id: if secgroup not passed -- the tenant in which to
960 search for default secgroup
961 :param kwargs: a dictionary containing rule parameters:
962 for example, to allow incoming ssh:
963 rule = {
964 direction: 'ingress'
965 protocol:'tcp',
966 port_range_min: 22,
967 port_range_max: 22
968 }
969 """
970 if client is None:
971 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300972 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000973 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300974 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300975 secgroup = self._default_security_group(client=client,
976 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300977
978 ruleset = dict(security_group_id=secgroup.id,
979 tenant_id=secgroup.tenant_id)
980 ruleset.update(kwargs)
981
David Kranz34e88122014-12-11 15:24:05 -0500982 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300983 sg_rule = net_resources.DeletableSecurityGroupRule(
984 client=client,
985 **sg_rule['security_group_rule']
986 )
987 self.addCleanup(self.delete_wrapper, sg_rule.delete)
988 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
989 self.assertEqual(secgroup.id, sg_rule.security_group_id)
990
991 return sg_rule
992
993 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
994 """These rules are intended to permit inbound ssh and icmp
995 traffic from all sources, so no group_id is provided.
996 Setting a group_id would only permit traffic from ports
997 belonging to the same security group.
998 """
999
1000 if client is None:
1001 client = self.network_client
1002 rules = []
1003 rulesets = [
1004 dict(
1005 # ssh
1006 protocol='tcp',
1007 port_range_min=22,
1008 port_range_max=22,
1009 ),
1010 dict(
1011 # ping
1012 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001013 ),
1014 dict(
1015 # ipv6-icmp for ping6
1016 protocol='icmp',
1017 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001018 )
1019 ]
1020 for ruleset in rulesets:
1021 for r_direction in ['ingress', 'egress']:
1022 ruleset['direction'] = r_direction
1023 try:
1024 sg_rule = self._create_security_group_rule(
1025 client=client, secgroup=secgroup, **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001026 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001027 # if rule already exist - skip rule and continue
1028 msg = 'Security group rule already exists'
1029 if msg not in ex._error_string:
1030 raise ex
1031 else:
1032 self.assertEqual(r_direction, sg_rule.direction)
1033 rules.append(sg_rule)
1034
1035 return rules
1036
1037 def _ssh_to_server(self, server, private_key):
1038 ssh_login = CONF.compute.image_ssh_user
1039 return self.get_remote_client(server,
1040 username=ssh_login,
1041 private_key=private_key)
1042
Yair Frieddb6c9e92014-08-06 08:53:13 +03001043 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001044 """Retrieve a router for the given tenant id.
1045
1046 If a public router has been configured, it will be returned.
1047
1048 If a public router has not been configured, but a public
1049 network has, a tenant router will be created and returned that
1050 routes traffic to the public network.
1051 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001052 if not client:
1053 client = self.network_client
1054 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001055 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001056 router_id = CONF.network.public_router_id
1057 network_id = CONF.network.public_network_id
1058 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001059 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +04001060 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001061 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001062 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001063 router.set_gateway(network_id)
1064 return router
1065 else:
1066 raise Exception("Neither of 'public_router_id' or "
1067 "'public_network_id' has been defined.")
1068
Yair Frieddb6c9e92014-08-06 08:53:13 +03001069 def _create_router(self, client=None, tenant_id=None,
1070 namestart='router-smoke'):
1071 if not client:
1072 client = self.network_client
1073 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001074 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001075 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001076 result = client.create_router(name=name,
1077 admin_state_up=True,
1078 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001079 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001080 **result['router'])
1081 self.assertEqual(router.name, name)
1082 self.addCleanup(self.delete_wrapper, router.delete)
1083 return router
1084
Alok Maurya6384bbb2014-07-13 06:44:29 -07001085 def _update_router_admin_state(self, router, admin_state_up):
1086 router.update(admin_state_up=admin_state_up)
1087 self.assertEqual(admin_state_up, router.admin_state_up)
1088
John Warren94d8faf2015-09-15 12:22:24 -04001089 def create_networks(self, client=None, networks_client=None,
John Warren3961acd2015-10-02 14:38:53 -04001090 subnets_client=None, tenant_id=None,
1091 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001092 """Create a network with a subnet connected to a router.
1093
David Shrewsbury9bac3662014-08-07 15:07:01 -04001094 The baremetal driver is a special case since all nodes are
1095 on the same shared network.
1096
Yair Fried413bf2d2014-11-19 17:07:11 +02001097 :param client: network client to create resources with.
1098 :param tenant_id: id of tenant to create resources in.
1099 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001100 :returns: network, subnet, router
1101 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001102 if CONF.baremetal.driver_enabled:
1103 # NOTE(Shrews): This exception is for environments where tenant
1104 # credential isolation is available, but network separation is
1105 # not (the current baremetal case). Likely can be removed when
1106 # test account mgmt is reworked:
1107 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001108 if not CONF.compute.fixed_network_name:
1109 m = 'fixed_network_name must be specified in config'
1110 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001111 network = self._get_network_by_name(
1112 CONF.compute.fixed_network_name)
1113 router = None
1114 subnet = None
1115 else:
John Warren94d8faf2015-09-15 12:22:24 -04001116 network = self._create_network(
1117 client=client, networks_client=networks_client,
1118 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001119 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001120
John Warren3961acd2015-10-02 14:38:53 -04001121 subnet_kwargs = dict(network=network, client=client,
1122 subnets_client=subnets_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001123 # use explicit check because empty list is a valid option
1124 if dns_nameservers is not None:
1125 subnet_kwargs['dns_nameservers'] = dns_nameservers
1126 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001127 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001128 return network, subnet, router
1129
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001130 def create_server(self, name=None, image=None, flavor=None,
1131 wait_on_boot=True, wait_on_delete=True,
John Warren94d8faf2015-09-15 12:22:24 -04001132 network_client=None, networks_client=None,
John Warren49c0fe52015-10-22 12:35:54 -04001133 ports_client=None, create_kwargs=None):
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001134 if network_client is None:
1135 network_client = self.network_client
John Warren94d8faf2015-09-15 12:22:24 -04001136 if networks_client is None:
1137 networks_client = self.networks_client
John Warren49c0fe52015-10-22 12:35:54 -04001138 if ports_client is None:
1139 ports_client = self.ports_client
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001140
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001141 vnic_type = CONF.network.port_vnic_type
1142
1143 # If vnic_type is configured create port for
1144 # every network
1145 if vnic_type:
1146 ports = []
1147 networks = []
1148 create_port_body = {'binding:vnic_type': vnic_type,
1149 'namestart': 'port-smoke'}
1150 if create_kwargs:
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001151 # Convert security group names to security group ids
1152 # to pass to create_port
1153 if create_kwargs.get('security_groups'):
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001154 security_groups = network_client.list_security_groups(
1155 ).get('security_groups')
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001156 sec_dict = dict([(s['name'], s['id'])
1157 for s in security_groups])
1158
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001159 sec_groups_names = [s['name'] for s in create_kwargs.get(
1160 'security_groups')]
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001161 security_groups_ids = [sec_dict[s]
1162 for s in sec_groups_names]
1163
1164 if security_groups_ids:
1165 create_port_body[
1166 'security_groups'] = security_groups_ids
1167 networks = create_kwargs.get('networks')
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001168
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001169 # If there are no networks passed to us we look up
1170 # for the tenant's private networks and create a port
1171 # if there is only one private network. The same behaviour
1172 # as we would expect when passing the call to the clients
1173 # with no networks
1174 if not networks:
John Warren94d8faf2015-09-15 12:22:24 -04001175 networks = networks_client.list_networks(filters={
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001176 'router:external': False})
1177 self.assertEqual(1, len(networks),
1178 "There is more than one"
1179 " network for the tenant")
1180 for net in networks:
1181 net_id = net['uuid']
1182 port = self._create_port(network_id=net_id,
John Warren49c0fe52015-10-22 12:35:54 -04001183 client=ports_client,
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001184 **create_port_body)
1185 ports.append({'port': port.id})
1186 if ports:
1187 create_kwargs['networks'] = ports
Shuquan Huangb5c8beb2015-08-05 14:14:01 +00001188 self.ports = ports
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001189
1190 return super(NetworkScenarioTest, self).create_server(
1191 name=name, image=image, flavor=flavor,
1192 wait_on_boot=wait_on_boot, wait_on_delete=wait_on_delete,
1193 create_kwargs=create_kwargs)
1194
Yair Fried1fc32a12014-08-04 09:11:30 +03001195
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001196# power/provision states as of icehouse
1197class BaremetalPowerStates(object):
1198 """Possible power states of an Ironic node."""
1199 POWER_ON = 'power on'
1200 POWER_OFF = 'power off'
1201 REBOOT = 'rebooting'
1202 SUSPEND = 'suspended'
1203
1204
1205class BaremetalProvisionStates(object):
1206 """Possible provision states of an Ironic node."""
1207 NOSTATE = None
1208 INIT = 'initializing'
1209 ACTIVE = 'active'
1210 BUILDING = 'building'
1211 DEPLOYWAIT = 'wait call-back'
1212 DEPLOYING = 'deploying'
1213 DEPLOYFAIL = 'deploy failed'
1214 DEPLOYDONE = 'deploy complete'
1215 DELETING = 'deleting'
1216 DELETED = 'deleted'
1217 ERROR = 'error'
1218
1219
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001220class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001221
1222 credentials = ['primary', 'admin']
1223
Adam Gandelman4a48a602014-03-20 18:23:18 -07001224 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001225 def skip_checks(cls):
1226 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001227 if (not CONF.service_available.ironic or
1228 not CONF.baremetal.driver_enabled):
1229 msg = 'Ironic not available or Ironic compute driver not enabled'
1230 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001231
1232 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001233 def setup_clients(cls):
1234 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001235
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001236 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001237
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001238 @classmethod
1239 def resource_setup(cls):
1240 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001241 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001242 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001243
1244 def _node_state_timeout(self, node_id, state_attr,
1245 target_states, timeout=10, interval=1):
1246 if not isinstance(target_states, list):
1247 target_states = [target_states]
1248
1249 def check_state():
1250 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001251 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001252 return True
1253 return False
1254
1255 if not tempest.test.call_until_true(
1256 check_state, timeout, interval):
1257 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1258 (node_id, state_attr, target_states))
1259 raise exceptions.TimeoutException(msg)
1260
1261 def wait_provisioning_state(self, node_id, state, timeout):
1262 self._node_state_timeout(
1263 node_id=node_id, state_attr='provision_state',
1264 target_states=state, timeout=timeout)
1265
1266 def wait_power_state(self, node_id, state):
1267 self._node_state_timeout(
1268 node_id=node_id, state_attr='power_state',
1269 target_states=state, timeout=CONF.baremetal.power_timeout)
1270
1271 def wait_node(self, instance_id):
1272 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001273
Adam Gandelman4a48a602014-03-20 18:23:18 -07001274 def _get_node():
1275 node = None
1276 try:
1277 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001278 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001279 pass
1280 return node is not None
1281
1282 if not tempest.test.call_until_true(
1283 _get_node, CONF.baremetal.association_timeout, 1):
1284 msg = ('Timed out waiting to get Ironic node by instance id %s'
1285 % instance_id)
1286 raise exceptions.TimeoutException(msg)
1287
1288 def get_node(self, node_id=None, instance_id=None):
1289 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001290 _, body = self.baremetal_client.show_node(node_id)
1291 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001292 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001293 _, body = self.baremetal_client.show_node_by_instance_uuid(
1294 instance_id)
1295 if body['nodes']:
1296 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001297
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001298 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001299 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001300 _, body = self.baremetal_client.list_node_ports(node_uuid)
1301 for port in body['ports']:
1302 _, p = self.baremetal_client.show_port(port['uuid'])
1303 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001304 return ports
1305
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001306 def add_keypair(self):
1307 self.keypair = self.create_keypair()
1308
1309 def verify_connectivity(self, ip=None):
1310 if ip:
1311 dest = self.get_remote_client(ip)
1312 else:
1313 dest = self.get_remote_client(self.instance)
1314 dest.validate_authentication()
1315
1316 def boot_instance(self):
1317 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001318 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001319 }
1320 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001321 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001322
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001323 self.wait_node(self.instance['id'])
1324 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001325
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001326 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001327
1328 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001329 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001330 [BaremetalProvisionStates.DEPLOYWAIT,
1331 BaremetalProvisionStates.ACTIVE],
1332 timeout=15)
1333
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001334 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001335 BaremetalProvisionStates.ACTIVE,
1336 timeout=CONF.baremetal.active_timeout)
1337
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001338 waiters.wait_for_server_status(self.servers_client,
1339 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001340 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001341 self.instance = (self.servers_client.show_server(self.instance['id'])
1342 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001343
1344 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001345 self.servers_client.delete_server(self.instance['id'])
1346 self.wait_power_state(self.node['uuid'],
1347 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001348 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001349 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001350 BaremetalProvisionStates.NOSTATE,
1351 timeout=CONF.baremetal.unprovision_timeout)
1352
Adam Gandelman4a48a602014-03-20 18:23:18 -07001353
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001354class EncryptionScenarioTest(ScenarioTest):
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001355 """
1356 Base class for encryption scenario tests
1357 """
1358
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001359 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001360
1361 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001362 def setup_clients(cls):
1363 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001364 if CONF.volume_feature_enabled.api_v1:
1365 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1366 else:
1367 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001368
1369 def _wait_for_volume_status(self, status):
1370 self.status_timeout(
1371 self.volume_client.volumes, self.volume.id, status)
1372
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001373 def nova_boot(self):
1374 self.keypair = self.create_keypair()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001375 create_kwargs = {'key_name': self.keypair['name']}
1376 self.server = self.create_server(image=self.image,
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001377 create_kwargs=create_kwargs)
1378
1379 def create_volume_type(self, client=None, name=None):
1380 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001381 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001382 if not name:
1383 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001384 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001385 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001386 body = client.create_volume_type(
John Warrend053ded2015-08-13 15:22:48 +00001387 randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001388 self.assertIn('id', body)
1389 self.addCleanup(client.delete_volume_type, body['id'])
1390 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001391
1392 def create_encryption_type(self, client=None, type_id=None, provider=None,
1393 key_size=None, cipher=None,
1394 control_location=None):
1395 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001396 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001397 if not type_id:
1398 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001399 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001400 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001401 client.create_encryption_type(
1402 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001403 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001404
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001405
Masayuki Igawa0870db52015-09-18 21:08:36 +09001406class ObjectStorageScenarioTest(ScenarioTest):
Chris Dent0d494112014-08-26 13:48:30 +01001407 """
Masayuki Igawa0870db52015-09-18 21:08:36 +09001408 Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001409
1410 Subclasses implement the tests that use the methods provided by this
1411 class.
1412 """
1413
1414 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001415 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001416 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001417 if not CONF.service_available.swift:
1418 skip_msg = ("%s skipped as swift is not available" %
1419 cls.__name__)
1420 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001421
1422 @classmethod
1423 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001424 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001425 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001426 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001427 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001428
1429 @classmethod
1430 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001431 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001432 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001433 cls.account_client = cls.os_operator.account_client
1434 cls.container_client = cls.os_operator.container_client
1435 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001436
Chris Dentde456a12014-09-10 12:41:15 +01001437 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001438 """get swift status for our user account."""
1439 self.account_client.list_account_containers()
1440 LOG.debug('Swift status information obtained successfully')
1441
Chris Dentde456a12014-09-10 12:41:15 +01001442 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001443 name = container_name or data_utils.rand_name(
1444 'swift-scenario-container')
1445 self.container_client.create_container(name)
1446 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001447 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001448 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001449 self.addCleanup(self.delete_wrapper,
1450 self.container_client.delete_container,
1451 name)
Chris Dent0d494112014-08-26 13:48:30 +01001452 return name
1453
Chris Dentde456a12014-09-10 12:41:15 +01001454 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001455 self.container_client.delete_container(container_name)
1456 LOG.debug('Container %s deleted' % (container_name))
1457
Chris Dentde456a12014-09-10 12:41:15 +01001458 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001459 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1460 obj_data = data_utils.arbitrary_string()
1461 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001462 self.addCleanup(self.delete_wrapper,
1463 self.object_client.delete_object,
1464 container_name,
1465 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001466 return obj_name, obj_data
1467
Chris Dentde456a12014-09-10 12:41:15 +01001468 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001469 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001470 self.list_and_check_container_objects(container_name,
1471 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001472
Chris Dentde456a12014-09-10 12:41:15 +01001473 def list_and_check_container_objects(self, container_name,
1474 present_obj=None,
1475 not_present_obj=None):
Chris Dent0d494112014-08-26 13:48:30 +01001476 """
1477 List objects for a given container and assert which are present and
1478 which are not.
1479 """
Ghanshyam2a180b82014-06-16 13:54:22 +09001480 if present_obj is None:
1481 present_obj = []
1482 if not_present_obj is None:
1483 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001484 _, object_list = self.container_client.list_container_contents(
1485 container_name)
1486 if present_obj:
1487 for obj in present_obj:
1488 self.assertIn(obj, object_list)
1489 if not_present_obj:
1490 for obj in not_present_obj:
1491 self.assertNotIn(obj, object_list)
1492
Chris Dentde456a12014-09-10 12:41:15 +01001493 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001494 metadata_param = {'metadata_prefix': 'x-container-',
1495 'metadata': {'read': acl}}
1496 self.container_client.update_container_metadata(container_name,
1497 **metadata_param)
1498 resp, _ = self.container_client.list_container_metadata(container_name)
1499 self.assertEqual(resp['x-container-read'], acl)
1500
Chris Dentde456a12014-09-10 12:41:15 +01001501 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001502 _, obj = self.object_client.get_object(container_name, obj_name)
1503 self.assertEqual(obj, expected_data)