blob: 9f283c5f41a5d1572914a8b2f5d244ed0a416c47 [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
John Warrene74890a2015-11-11 15:18:01 -050050 cls.compute_floating_ips_client = (
51 cls.manager.compute_floating_ips_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +010052 # Glance image client v1
53 cls.image_client = cls.manager.image_client
nithya-ganesan882595e2014-07-29 18:51:07 +000054 # Compute image client
55 cls.images_client = cls.manager.images_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010056 cls.keypairs_client = cls.manager.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +010057 # Nova security groups client
58 cls.security_groups_client = cls.manager.security_groups_client
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +000059 cls.security_group_rules_client = (
60 cls.manager.security_group_rules_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +010061 cls.servers_client = cls.manager.servers_client
Yair Fried1fc32a12014-08-04 09:11:30 +030062 cls.interface_client = cls.manager.interfaces_client
63 # Neutron network client
64 cls.network_client = cls.manager.network_client
John Warren94d8faf2015-09-15 12:22:24 -040065 cls.networks_client = cls.manager.networks_client
John Warren49c0fe52015-10-22 12:35:54 -040066 cls.ports_client = cls.manager.ports_client
John Warren3961acd2015-10-02 14:38:53 -040067 cls.subnets_client = cls.manager.subnets_client
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090068 # Heat client
69 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010070
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030071 if CONF.volume_feature_enabled.api_v1:
72 cls.volumes_client = cls.manager.volumes_client
73 cls.snapshots_client = cls.manager.snapshots_client
74 else:
75 cls.volumes_client = cls.manager.volumes_v2_client
76 cls.snapshots_client = cls.manager.snapshots_v2_client
77
Andrea Frittoli247058f2014-07-16 16:09:22 +010078 # ## Methods to handle sync and async deletes
79
80 def setUp(self):
81 super(ScenarioTest, self).setUp()
82 self.cleanup_waits = []
83 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
84 # because scenario tests in the same test class should not share
85 # resources. If resources were shared between test cases then it
86 # should be a single scenario test instead of multiples.
87
88 # NOTE(yfried): this list is cleaned at the end of test_methods and
89 # not at the end of the class
90 self.addCleanup(self._wait_for_cleanups)
91
Yair Fried1fc32a12014-08-04 09:11:30 +030092 def delete_wrapper(self, delete_thing, *args, **kwargs):
Andrea Frittoli247058f2014-07-16 16:09:22 +010093 """Ignores NotFound exceptions for delete operations.
94
Yair Fried1fc32a12014-08-04 09:11:30 +030095 @param delete_thing: delete method of a resource. method will be
96 executed as delete_thing(*args, **kwargs)
97
Andrea Frittoli247058f2014-07-16 16:09:22 +010098 """
99 try:
100 # Tempest clients return dicts, so there is no common delete
101 # method available. Using a callable instead
Yair Fried1fc32a12014-08-04 09:11:30 +0300102 delete_thing(*args, **kwargs)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900103 except lib_exc.NotFound:
Andrea Frittoli247058f2014-07-16 16:09:22 +0100104 # If the resource is already missing, mission accomplished.
105 pass
106
107 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +0900108 cleanup_callable, cleanup_args=None,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000109 cleanup_kwargs=None, waiter_client=None):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700110 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100111
112 @param waiter_callable: callable to wait for the resource to delete
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000113 with the following waiter_client if specified.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100114 @param thing_id: the id of the resource to be cleaned-up
115 @param thing_id_param: the name of the id param in the waiter
116 @param cleanup_callable: method to load pass to self.addCleanup with
117 the following *cleanup_args, **cleanup_kwargs.
118 usually a delete method.
119 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900120 if cleanup_args is None:
121 cleanup_args = []
122 if cleanup_kwargs is None:
123 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100124 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
125 wait_dict = {
126 'waiter_callable': waiter_callable,
127 thing_id_param: thing_id
128 }
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000129 if waiter_client:
130 wait_dict['client'] = waiter_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100131 self.cleanup_waits.append(wait_dict)
132
133 def _wait_for_cleanups(self):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000134 # To handle async delete actions, a list of waits is added
135 # which will be iterated over as the last step of clearing the
136 # cleanup queue. That way all the delete calls are made up front
137 # and the tests won't succeed unless the deletes are eventually
138 # successful. This is the same basic approach used in the api tests to
139 # limit cleanup execution time except here it is multi-resource,
140 # because of the nature of the scenario tests.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100141 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):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000521 """Check server connectivity
522
Yair Friedae0e73d2014-11-24 11:56:26 +0200523 :param ip_address: server to test against
524 :param username: server's ssh username
525 :param private_key: server's ssh private key to be used
526 :param should_connect: True/False indicates positive/negative test
527 positive - attempt ping and ssh
528 negative - attempt ping and fail if succeed
529
530 :raises: AssertError if the result of the connectivity check does
531 not match the value of the should_connect param
532 """
533 if should_connect:
534 msg = "Timed out waiting for %s to become reachable" % ip_address
535 else:
536 msg = "ip address %s is reachable" % ip_address
537 self.assertTrue(self.ping_ip_address(ip_address,
538 should_succeed=should_connect),
539 msg=msg)
540 if should_connect:
541 # no need to check ssh for negative connectivity
542 self.get_remote_client(ip_address, username, private_key)
543
544 def check_public_network_connectivity(self, ip_address, username,
545 private_key, should_connect=True,
546 msg=None, servers=None):
547 # The target login is assumed to have been configured for
548 # key-based authentication by cloud-init.
549 LOG.debug('checking network connections to IP %s with user: %s' %
550 (ip_address, username))
551 try:
552 self.check_vm_connectivity(ip_address,
553 username,
554 private_key,
555 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500556 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200557 ex_msg = 'Public network connectivity check failed'
558 if msg:
559 ex_msg += ": " + msg
560 LOG.exception(ex_msg)
561 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200562 raise
563
564 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000565 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200566
John Warrene74890a2015-11-11 15:18:01 -0500567 floating_ip = (self.compute_floating_ips_client.
568 create_floating_ip(pool_name)['floating_ip'])
Yair Friedae0e73d2014-11-24 11:56:26 +0200569 self.addCleanup(self.delete_wrapper,
John Warrene74890a2015-11-11 15:18:01 -0500570 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200571 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500572 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200573 floating_ip['ip'], thing['id'])
574 return floating_ip
575
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700576 def create_timestamp(self, server_or_ip, dev_name=None, mount_path='/mnt',
577 private_key=None):
578 ssh_client = self.get_remote_client(server_or_ip,
579 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300580 if dev_name is not None:
581 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700582 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300583 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
584 ssh_client.exec_command(cmd_timestamp)
585 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
586 % mount_path)
587 if dev_name is not None:
588 ssh_client.umount(mount_path)
589 return timestamp
590
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700591 def get_timestamp(self, server_or_ip, dev_name=None, mount_path='/mnt',
592 private_key=None):
593 ssh_client = self.get_remote_client(server_or_ip,
594 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300595 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700596 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300597 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
598 % mount_path)
599 if dev_name is not None:
600 ssh_client.umount(mount_path)
601 return timestamp
602
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200603 def get_server_or_ip(self, server):
604 if CONF.validation.connect_method == 'floating':
605 ip = self.create_floating_ip(server)['ip']
606 else:
607 ip = server
608 return ip
609
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100610
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100611class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300612 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000613
Yair Fried1fc32a12014-08-04 09:11:30 +0300614 This class provide helpers for network scenario tests, using the neutron
615 API. Helpers from ancestor which use the nova network API are overridden
616 with the neutron API.
617
618 This Class also enforces using Neutron instead of novanetwork.
619 Subclassed tests will be skipped if Neutron is not enabled
620
621 """
622
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000623 credentials = ['primary', 'admin']
624
Yair Fried1fc32a12014-08-04 09:11:30 +0300625 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000626 def skip_checks(cls):
627 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100628 if not CONF.service_available.neutron:
629 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300630
631 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100632 def resource_setup(cls):
633 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300634 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300635
John Warren94d8faf2015-09-15 12:22:24 -0400636 def _create_network(self, client=None, networks_client=None,
637 tenant_id=None, namestart='network-smoke-'):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300638 if not client:
639 client = self.network_client
John Warren94d8faf2015-09-15 12:22:24 -0400640 if not networks_client:
641 networks_client = self.networks_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300642 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000643 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300644 name = data_utils.rand_name(namestart)
John Warren94d8faf2015-09-15 12:22:24 -0400645 result = networks_client.create_network(name=name, tenant_id=tenant_id)
646 network = net_resources.DeletableNetwork(
647 networks_client=networks_client, **result['network'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300648 self.assertEqual(network.name, name)
649 self.addCleanup(self.delete_wrapper, network.delete)
650 return network
651
652 def _list_networks(self, *args, **kwargs):
653 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400654 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900655 *args, **kwargs)
656 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300657
658 def _list_subnets(self, *args, **kwargs):
659 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400660 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900661 *args, **kwargs)
662 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300663
664 def _list_routers(self, *args, **kwargs):
665 """List routers using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900666 routers_list = self.admin_manager.network_client.list_routers(
667 *args, **kwargs)
668 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300669
670 def _list_ports(self, *args, **kwargs):
671 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400672 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900673 *args, **kwargs)
674 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300675
Yair Fried564d89d2015-08-06 17:02:12 +0300676 def _list_agents(self, *args, **kwargs):
677 """List agents using admin creds """
678 agents_list = self.admin_manager.network_client.list_agents(
679 *args, **kwargs)
680 return agents_list['agents']
681
John Warren3961acd2015-10-02 14:38:53 -0400682 def _create_subnet(self, network, client=None, subnets_client=None,
683 namestart='subnet-smoke', **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000684 """Create a subnet for the given network
685
686 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300687 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300688 if not client:
689 client = self.network_client
John Warren3961acd2015-10-02 14:38:53 -0400690 if not subnets_client:
691 subnets_client = self.subnets_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300692
693 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000694 """Check cidr existence
695
Yair Fried1fc32a12014-08-04 09:11:30 +0300696 :return True if subnet with cidr already exist in tenant
697 False else
698 """
699 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
700 return len(cidr_in_use) != 0
701
Kirill Shileev14113572014-11-21 16:58:02 +0300702 ip_version = kwargs.pop('ip_version', 4)
703
704 if ip_version == 6:
705 tenant_cidr = netaddr.IPNetwork(
706 CONF.network.tenant_network_v6_cidr)
707 num_bits = CONF.network.tenant_network_v6_mask_bits
708 else:
709 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
710 num_bits = CONF.network.tenant_network_mask_bits
711
Yair Fried1fc32a12014-08-04 09:11:30 +0300712 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300713 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300714 # Repeatedly attempt subnet creation with sequential cidr
715 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300716 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300717 str_cidr = str(subnet_cidr)
718 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
719 continue
720
721 subnet = dict(
722 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300723 network_id=network.id,
724 tenant_id=network.tenant_id,
725 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300726 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300727 **kwargs
728 )
729 try:
John Warren3961acd2015-10-02 14:38:53 -0400730 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300731 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900732 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300733 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
734 if not is_overlapping_cidr:
735 raise
736 self.assertIsNotNone(result, 'Unable to allocate tenant network')
John Warren3961acd2015-10-02 14:38:53 -0400737 subnet = net_resources.DeletableSubnet(
738 network_client=client, subnets_client=subnets_client,
739 **result['subnet'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300740 self.assertEqual(subnet.cidr, str_cidr)
741 self.addCleanup(self.delete_wrapper, subnet.delete)
742 return subnet
743
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200744 def _create_port(self, network_id, client=None, namestart='port-quotatest',
745 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300746 if not client:
John Warren49c0fe52015-10-22 12:35:54 -0400747 client = self.ports_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300748 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500749 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300750 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200751 network_id=network_id,
752 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300753 self.assertIsNotNone(result, 'Unable to allocate port')
John Warren49c0fe52015-10-22 12:35:54 -0400754 port = net_resources.DeletablePort(ports_client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300755 **result['port'])
756 self.addCleanup(self.delete_wrapper, port.delete)
757 return port
758
Kirill Shileev14113572014-11-21 16:58:02 +0300759 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Ken'ichi Ohmichi30b769e2015-10-14 09:47:22 +0000760 ports = self._list_ports(device_id=server['id'], status='ACTIVE',
Yair Fried1fc32a12014-08-04 09:11:30 +0300761 fixed_ip=ip_addr)
Kirill Shileev14113572014-11-21 16:58:02 +0300762 # it might happen here that this port has more then one ip address
763 # as in case of dual stack- when this port is created on 2 subnets
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200764 port_map = [(p["id"], fxip["ip_address"])
765 for p in ports
766 for fxip in p["fixed_ips"]
767 if netaddr.valid_ipv4(fxip["ip_address"])]
768
John L. Villalovosb83286f2015-11-04 14:46:57 -0800769 self.assertNotEqual(0, len(port_map),
770 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200771 self.assertEqual(len(port_map), 1,
772 "Found multiple IPv4 addresses: %s. "
773 "Unable to determine which port to target."
774 % port_map)
775 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300776
David Shrewsbury9bac3662014-08-07 15:07:01 -0400777 def _get_network_by_name(self, network_name):
778 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700779 self.assertNotEqual(len(net), 0,
780 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300781 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400782
Yair Friedae0e73d2014-11-24 11:56:26 +0200783 def create_floating_ip(self, thing, external_network_id=None,
784 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000785 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200786 if not external_network_id:
787 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300788 if not client:
789 client = self.network_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300790 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300791 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
792 else:
793 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500794 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300795 floating_network_id=external_network_id,
796 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300797 tenant_id=thing['tenant_id'],
798 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300799 )
800 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300801 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300802 **result['floatingip'])
803 self.addCleanup(self.delete_wrapper, floating_ip.delete)
804 return floating_ip
805
806 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300807 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300808 floating_ip.update(port_id=port_id)
809 self.assertEqual(port_id, floating_ip.port_id)
810 return floating_ip
811
812 def _disassociate_floating_ip(self, floating_ip):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000813 """:param floating_ip: type DeletableFloatingIp"""
Yair Fried1fc32a12014-08-04 09:11:30 +0300814 floating_ip.update(port_id=None)
815 self.assertIsNone(floating_ip.port_id)
816 return floating_ip
817
Yair Fried45f92952014-06-26 05:19:19 +0300818 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000819 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300820
821 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
822 to check status
823 :param status: target status
824 :raises: AssertionError if status doesn't match
825 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000826 def refresh():
827 floating_ip.refresh()
828 return status == floating_ip.status
829
830 tempest.test.call_until_true(refresh,
831 CONF.network.build_timeout,
832 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300833 self.assertEqual(status, floating_ip.status,
834 message="FloatingIP: {fp} is at status: {cst}. "
835 "failed to reach status: {st}"
836 .format(fp=floating_ip, cst=floating_ip.status,
837 st=status))
838 LOG.info("FloatingIP: {fp} is at status: {st}"
839 .format(fp=floating_ip, st=status))
840
Yair Fried1fc32a12014-08-04 09:11:30 +0300841 def _check_tenant_network_connectivity(self, server,
842 username,
843 private_key,
844 should_connect=True,
845 servers_for_debug=None):
846 if not CONF.network.tenant_networks_reachable:
847 msg = 'Tenant networks not configured to be reachable.'
848 LOG.info(msg)
849 return
850 # The target login is assumed to have been configured for
851 # key-based authentication by cloud-init.
852 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400853 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300854 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900855 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200856 username,
857 private_key,
858 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300859 except Exception as e:
860 LOG.exception('Tenant network connectivity check failed')
861 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000862 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300863 raise
864
865 def _check_remote_connectivity(self, source, dest, should_succeed=True):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000866 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300867
868 :param source: RemoteClient: an ssh connection from which to ping
869 :param dest: and IP to ping against
870 :param should_succeed: boolean should ping succeed or not
871 :returns: boolean -- should_succeed == ping
872 :returns: ping is false if ping failed
873 """
874 def ping_remote():
875 try:
876 source.ping_host(dest)
Andrey Pavlov64723762015-04-29 06:24:58 +0300877 except lib_exc.SSHExecCommandFailed:
Yair Fried1fc32a12014-08-04 09:11:30 +0300878 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
879 % (dest, source.ssh_client.host))
880 return not should_succeed
881 return should_succeed
882
883 return tempest.test.call_until_true(ping_remote,
884 CONF.compute.ping_timeout,
885 1)
886
Yair Frieddb6c9e92014-08-06 08:53:13 +0300887 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300888 namestart='secgroup-smoke'):
889 if client is None:
890 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300891 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000892 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300893 secgroup = self._create_empty_security_group(namestart=namestart,
894 client=client,
895 tenant_id=tenant_id)
896
897 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900898 rules = self._create_loginable_secgroup_rule(client=client,
899 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300900 for rule in rules:
901 self.assertEqual(tenant_id, rule.tenant_id)
902 self.assertEqual(secgroup.id, rule.security_group_id)
903 return secgroup
904
Yair Frieddb6c9e92014-08-06 08:53:13 +0300905 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300906 namestart='secgroup-smoke'):
907 """Create a security group without rules.
908
909 Default rules will be created:
910 - IPv4 egress to any
911 - IPv6 egress to any
912
913 :param tenant_id: secgroup will be created in this tenant
914 :returns: DeletableSecurityGroup -- containing the secgroup created
915 """
916 if client is None:
917 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300918 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000919 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300920 sg_name = data_utils.rand_name(namestart)
921 sg_desc = sg_name + " description"
922 sg_dict = dict(name=sg_name,
923 description=sg_desc)
924 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500925 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300926 secgroup = net_resources.DeletableSecurityGroup(
927 client=client,
928 **result['security_group']
929 )
930 self.assertEqual(secgroup.name, sg_name)
931 self.assertEqual(tenant_id, secgroup.tenant_id)
932 self.assertEqual(secgroup.description, sg_desc)
933 self.addCleanup(self.delete_wrapper, secgroup.delete)
934 return secgroup
935
Yair Frieddb6c9e92014-08-06 08:53:13 +0300936 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300937 """Get default secgroup for given tenant_id.
938
939 :returns: DeletableSecurityGroup -- default secgroup for given tenant
940 """
941 if client is None:
942 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300943 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000944 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300945 sgs = [
946 sg for sg in client.list_security_groups().values()[0]
947 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
948 ]
949 msg = "No default security group for tenant %s." % (tenant_id)
950 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300951 return net_resources.DeletableSecurityGroup(client=client,
952 **sgs[0])
953
Yair Frieddb6c9e92014-08-06 08:53:13 +0300954 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300955 tenant_id=None, **kwargs):
956 """Create a rule from a dictionary of rule parameters.
957
958 Create a rule in a secgroup. if secgroup not defined will search for
959 default secgroup in tenant_id.
960
961 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300962 :param tenant_id: if secgroup not passed -- the tenant in which to
963 search for default secgroup
964 :param kwargs: a dictionary containing rule parameters:
965 for example, to allow incoming ssh:
966 rule = {
967 direction: 'ingress'
968 protocol:'tcp',
969 port_range_min: 22,
970 port_range_max: 22
971 }
972 """
973 if client is None:
974 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300975 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000976 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300977 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300978 secgroup = self._default_security_group(client=client,
979 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300980
981 ruleset = dict(security_group_id=secgroup.id,
982 tenant_id=secgroup.tenant_id)
983 ruleset.update(kwargs)
984
David Kranz34e88122014-12-11 15:24:05 -0500985 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300986 sg_rule = net_resources.DeletableSecurityGroupRule(
987 client=client,
988 **sg_rule['security_group_rule']
989 )
990 self.addCleanup(self.delete_wrapper, sg_rule.delete)
991 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
992 self.assertEqual(secgroup.id, sg_rule.security_group_id)
993
994 return sg_rule
995
996 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000997 """Create loginable security group rule
998
999 These rules are intended to permit inbound ssh and icmp
Yair Fried1fc32a12014-08-04 09:11:30 +03001000 traffic from all sources, so no group_id is provided.
1001 Setting a group_id would only permit traffic from ports
1002 belonging to the same security group.
1003 """
1004
1005 if client is None:
1006 client = self.network_client
1007 rules = []
1008 rulesets = [
1009 dict(
1010 # ssh
1011 protocol='tcp',
1012 port_range_min=22,
1013 port_range_max=22,
1014 ),
1015 dict(
1016 # ping
1017 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001018 ),
1019 dict(
1020 # ipv6-icmp for ping6
1021 protocol='icmp',
1022 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001023 )
1024 ]
1025 for ruleset in rulesets:
1026 for r_direction in ['ingress', 'egress']:
1027 ruleset['direction'] = r_direction
1028 try:
1029 sg_rule = self._create_security_group_rule(
1030 client=client, secgroup=secgroup, **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001031 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001032 # if rule already exist - skip rule and continue
1033 msg = 'Security group rule already exists'
1034 if msg not in ex._error_string:
1035 raise ex
1036 else:
1037 self.assertEqual(r_direction, sg_rule.direction)
1038 rules.append(sg_rule)
1039
1040 return rules
1041
1042 def _ssh_to_server(self, server, private_key):
1043 ssh_login = CONF.compute.image_ssh_user
1044 return self.get_remote_client(server,
1045 username=ssh_login,
1046 private_key=private_key)
1047
Yair Frieddb6c9e92014-08-06 08:53:13 +03001048 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001049 """Retrieve a router for the given tenant id.
1050
1051 If a public router has been configured, it will be returned.
1052
1053 If a public router has not been configured, but a public
1054 network has, a tenant router will be created and returned that
1055 routes traffic to the public network.
1056 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001057 if not client:
1058 client = self.network_client
1059 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001060 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001061 router_id = CONF.network.public_router_id
1062 network_id = CONF.network.public_network_id
1063 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001064 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +04001065 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001066 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001067 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001068 router.set_gateway(network_id)
1069 return router
1070 else:
1071 raise Exception("Neither of 'public_router_id' or "
1072 "'public_network_id' has been defined.")
1073
Yair Frieddb6c9e92014-08-06 08:53:13 +03001074 def _create_router(self, client=None, tenant_id=None,
1075 namestart='router-smoke'):
1076 if not client:
1077 client = self.network_client
1078 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001079 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001080 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001081 result = client.create_router(name=name,
1082 admin_state_up=True,
1083 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001084 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001085 **result['router'])
1086 self.assertEqual(router.name, name)
1087 self.addCleanup(self.delete_wrapper, router.delete)
1088 return router
1089
Alok Maurya6384bbb2014-07-13 06:44:29 -07001090 def _update_router_admin_state(self, router, admin_state_up):
1091 router.update(admin_state_up=admin_state_up)
1092 self.assertEqual(admin_state_up, router.admin_state_up)
1093
John Warren94d8faf2015-09-15 12:22:24 -04001094 def create_networks(self, client=None, networks_client=None,
John Warren3961acd2015-10-02 14:38:53 -04001095 subnets_client=None, tenant_id=None,
1096 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001097 """Create a network with a subnet connected to a router.
1098
David Shrewsbury9bac3662014-08-07 15:07:01 -04001099 The baremetal driver is a special case since all nodes are
1100 on the same shared network.
1101
Yair Fried413bf2d2014-11-19 17:07:11 +02001102 :param client: network client to create resources with.
1103 :param tenant_id: id of tenant to create resources in.
1104 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001105 :returns: network, subnet, router
1106 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001107 if CONF.baremetal.driver_enabled:
1108 # NOTE(Shrews): This exception is for environments where tenant
1109 # credential isolation is available, but network separation is
1110 # not (the current baremetal case). Likely can be removed when
1111 # test account mgmt is reworked:
1112 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001113 if not CONF.compute.fixed_network_name:
1114 m = 'fixed_network_name must be specified in config'
1115 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001116 network = self._get_network_by_name(
1117 CONF.compute.fixed_network_name)
1118 router = None
1119 subnet = None
1120 else:
John Warren94d8faf2015-09-15 12:22:24 -04001121 network = self._create_network(
1122 client=client, networks_client=networks_client,
1123 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001124 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001125
John Warren3961acd2015-10-02 14:38:53 -04001126 subnet_kwargs = dict(network=network, client=client,
1127 subnets_client=subnets_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001128 # use explicit check because empty list is a valid option
1129 if dns_nameservers is not None:
1130 subnet_kwargs['dns_nameservers'] = dns_nameservers
1131 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001132 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001133 return network, subnet, router
1134
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001135 def create_server(self, name=None, image=None, flavor=None,
1136 wait_on_boot=True, wait_on_delete=True,
John Warren94d8faf2015-09-15 12:22:24 -04001137 network_client=None, networks_client=None,
John Warren49c0fe52015-10-22 12:35:54 -04001138 ports_client=None, create_kwargs=None):
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001139 if network_client is None:
1140 network_client = self.network_client
John Warren94d8faf2015-09-15 12:22:24 -04001141 if networks_client is None:
1142 networks_client = self.networks_client
John Warren49c0fe52015-10-22 12:35:54 -04001143 if ports_client is None:
1144 ports_client = self.ports_client
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001145
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001146 vnic_type = CONF.network.port_vnic_type
1147
1148 # If vnic_type is configured create port for
1149 # every network
1150 if vnic_type:
1151 ports = []
1152 networks = []
1153 create_port_body = {'binding:vnic_type': vnic_type,
1154 'namestart': 'port-smoke'}
1155 if create_kwargs:
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001156 # Convert security group names to security group ids
1157 # to pass to create_port
1158 if create_kwargs.get('security_groups'):
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001159 security_groups = network_client.list_security_groups(
1160 ).get('security_groups')
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001161 sec_dict = dict([(s['name'], s['id'])
1162 for s in security_groups])
1163
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001164 sec_groups_names = [s['name'] for s in create_kwargs.get(
1165 'security_groups')]
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001166 security_groups_ids = [sec_dict[s]
1167 for s in sec_groups_names]
1168
1169 if security_groups_ids:
1170 create_port_body[
1171 'security_groups'] = security_groups_ids
1172 networks = create_kwargs.get('networks')
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001173
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001174 # If there are no networks passed to us we look up
1175 # for the tenant's private networks and create a port
1176 # if there is only one private network. The same behaviour
1177 # as we would expect when passing the call to the clients
1178 # with no networks
1179 if not networks:
John Warren94d8faf2015-09-15 12:22:24 -04001180 networks = networks_client.list_networks(filters={
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001181 'router:external': False})
1182 self.assertEqual(1, len(networks),
1183 "There is more than one"
1184 " network for the tenant")
1185 for net in networks:
1186 net_id = net['uuid']
1187 port = self._create_port(network_id=net_id,
John Warren49c0fe52015-10-22 12:35:54 -04001188 client=ports_client,
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001189 **create_port_body)
1190 ports.append({'port': port.id})
1191 if ports:
1192 create_kwargs['networks'] = ports
Shuquan Huangb5c8beb2015-08-05 14:14:01 +00001193 self.ports = ports
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001194
1195 return super(NetworkScenarioTest, self).create_server(
1196 name=name, image=image, flavor=flavor,
1197 wait_on_boot=wait_on_boot, wait_on_delete=wait_on_delete,
1198 create_kwargs=create_kwargs)
1199
Yair Fried1fc32a12014-08-04 09:11:30 +03001200
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001201# power/provision states as of icehouse
1202class BaremetalPowerStates(object):
1203 """Possible power states of an Ironic node."""
1204 POWER_ON = 'power on'
1205 POWER_OFF = 'power off'
1206 REBOOT = 'rebooting'
1207 SUSPEND = 'suspended'
1208
1209
1210class BaremetalProvisionStates(object):
1211 """Possible provision states of an Ironic node."""
1212 NOSTATE = None
1213 INIT = 'initializing'
1214 ACTIVE = 'active'
1215 BUILDING = 'building'
1216 DEPLOYWAIT = 'wait call-back'
1217 DEPLOYING = 'deploying'
1218 DEPLOYFAIL = 'deploy failed'
1219 DEPLOYDONE = 'deploy complete'
1220 DELETING = 'deleting'
1221 DELETED = 'deleted'
1222 ERROR = 'error'
1223
1224
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001225class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001226
1227 credentials = ['primary', 'admin']
1228
Adam Gandelman4a48a602014-03-20 18:23:18 -07001229 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001230 def skip_checks(cls):
1231 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001232 if (not CONF.service_available.ironic or
1233 not CONF.baremetal.driver_enabled):
1234 msg = 'Ironic not available or Ironic compute driver not enabled'
1235 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001236
1237 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001238 def setup_clients(cls):
1239 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001240
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001241 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001242
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001243 @classmethod
1244 def resource_setup(cls):
1245 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001246 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001247 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001248
1249 def _node_state_timeout(self, node_id, state_attr,
1250 target_states, timeout=10, interval=1):
1251 if not isinstance(target_states, list):
1252 target_states = [target_states]
1253
1254 def check_state():
1255 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001256 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001257 return True
1258 return False
1259
1260 if not tempest.test.call_until_true(
1261 check_state, timeout, interval):
1262 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1263 (node_id, state_attr, target_states))
1264 raise exceptions.TimeoutException(msg)
1265
1266 def wait_provisioning_state(self, node_id, state, timeout):
1267 self._node_state_timeout(
1268 node_id=node_id, state_attr='provision_state',
1269 target_states=state, timeout=timeout)
1270
1271 def wait_power_state(self, node_id, state):
1272 self._node_state_timeout(
1273 node_id=node_id, state_attr='power_state',
1274 target_states=state, timeout=CONF.baremetal.power_timeout)
1275
1276 def wait_node(self, instance_id):
1277 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001278
Adam Gandelman4a48a602014-03-20 18:23:18 -07001279 def _get_node():
1280 node = None
1281 try:
1282 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001283 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001284 pass
1285 return node is not None
1286
1287 if not tempest.test.call_until_true(
1288 _get_node, CONF.baremetal.association_timeout, 1):
1289 msg = ('Timed out waiting to get Ironic node by instance id %s'
1290 % instance_id)
1291 raise exceptions.TimeoutException(msg)
1292
1293 def get_node(self, node_id=None, instance_id=None):
1294 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001295 _, body = self.baremetal_client.show_node(node_id)
1296 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001297 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001298 _, body = self.baremetal_client.show_node_by_instance_uuid(
1299 instance_id)
1300 if body['nodes']:
1301 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001302
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001303 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001304 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001305 _, body = self.baremetal_client.list_node_ports(node_uuid)
1306 for port in body['ports']:
1307 _, p = self.baremetal_client.show_port(port['uuid'])
1308 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001309 return ports
1310
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001311 def add_keypair(self):
1312 self.keypair = self.create_keypair()
1313
1314 def verify_connectivity(self, ip=None):
1315 if ip:
1316 dest = self.get_remote_client(ip)
1317 else:
1318 dest = self.get_remote_client(self.instance)
1319 dest.validate_authentication()
1320
1321 def boot_instance(self):
1322 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001323 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001324 }
1325 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001326 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001327
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001328 self.wait_node(self.instance['id'])
1329 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001330
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001331 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001332
1333 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001334 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001335 [BaremetalProvisionStates.DEPLOYWAIT,
1336 BaremetalProvisionStates.ACTIVE],
1337 timeout=15)
1338
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001339 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001340 BaremetalProvisionStates.ACTIVE,
1341 timeout=CONF.baremetal.active_timeout)
1342
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001343 waiters.wait_for_server_status(self.servers_client,
1344 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001345 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001346 self.instance = (self.servers_client.show_server(self.instance['id'])
1347 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001348
1349 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001350 self.servers_client.delete_server(self.instance['id'])
1351 self.wait_power_state(self.node['uuid'],
1352 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001353 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001354 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001355 BaremetalProvisionStates.NOSTATE,
1356 timeout=CONF.baremetal.unprovision_timeout)
1357
Adam Gandelman4a48a602014-03-20 18:23:18 -07001358
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001359class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001360 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001361
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001362 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001363
1364 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001365 def setup_clients(cls):
1366 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001367 if CONF.volume_feature_enabled.api_v1:
1368 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1369 else:
1370 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001371
1372 def _wait_for_volume_status(self, status):
1373 self.status_timeout(
1374 self.volume_client.volumes, self.volume.id, status)
1375
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001376 def nova_boot(self):
1377 self.keypair = self.create_keypair()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001378 create_kwargs = {'key_name': self.keypair['name']}
1379 self.server = self.create_server(image=self.image,
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001380 create_kwargs=create_kwargs)
1381
1382 def create_volume_type(self, client=None, name=None):
1383 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001384 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001385 if not name:
1386 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001387 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001388 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001389 body = client.create_volume_type(
John Warrend053ded2015-08-13 15:22:48 +00001390 randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001391 self.assertIn('id', body)
1392 self.addCleanup(client.delete_volume_type, body['id'])
1393 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001394
1395 def create_encryption_type(self, client=None, type_id=None, provider=None,
1396 key_size=None, cipher=None,
1397 control_location=None):
1398 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001399 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001400 if not type_id:
1401 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001402 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001403 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001404 client.create_encryption_type(
1405 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001406 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001407
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001408
Masayuki Igawa0870db52015-09-18 21:08:36 +09001409class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001410 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001411
1412 Subclasses implement the tests that use the methods provided by this
1413 class.
1414 """
1415
1416 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001417 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001418 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001419 if not CONF.service_available.swift:
1420 skip_msg = ("%s skipped as swift is not available" %
1421 cls.__name__)
1422 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001423
1424 @classmethod
1425 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001426 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001427 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001428 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001429 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001430
1431 @classmethod
1432 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001433 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001434 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001435 cls.account_client = cls.os_operator.account_client
1436 cls.container_client = cls.os_operator.container_client
1437 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001438
Chris Dentde456a12014-09-10 12:41:15 +01001439 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001440 """get swift status for our user account."""
1441 self.account_client.list_account_containers()
1442 LOG.debug('Swift status information obtained successfully')
1443
Chris Dentde456a12014-09-10 12:41:15 +01001444 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001445 name = container_name or data_utils.rand_name(
1446 'swift-scenario-container')
1447 self.container_client.create_container(name)
1448 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001449 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001450 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001451 self.addCleanup(self.delete_wrapper,
1452 self.container_client.delete_container,
1453 name)
Chris Dent0d494112014-08-26 13:48:30 +01001454 return name
1455
Chris Dentde456a12014-09-10 12:41:15 +01001456 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001457 self.container_client.delete_container(container_name)
1458 LOG.debug('Container %s deleted' % (container_name))
1459
Chris Dentde456a12014-09-10 12:41:15 +01001460 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001461 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1462 obj_data = data_utils.arbitrary_string()
1463 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001464 self.addCleanup(self.delete_wrapper,
1465 self.object_client.delete_object,
1466 container_name,
1467 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001468 return obj_name, obj_data
1469
Chris Dentde456a12014-09-10 12:41:15 +01001470 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001471 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001472 self.list_and_check_container_objects(container_name,
1473 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001474
Chris Dentde456a12014-09-10 12:41:15 +01001475 def list_and_check_container_objects(self, container_name,
1476 present_obj=None,
1477 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001478 # List objects for a given container and assert which are present and
1479 # which are not.
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)