blob: ed65c42bba2d886a49196e9f07f79a84083f58c1 [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
John Warrenfbf2a892015-11-17 12:36:14 -050068 cls.floating_ips_client = cls.manager.floating_ips_client
Masayuki Igawabc6fe8d2014-08-29 16:50:01 +090069 # Heat client
70 cls.orchestration_client = cls.manager.orchestration_client
Andrea Frittoli2e733b52014-07-16 14:12:11 +010071
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +030072 if CONF.volume_feature_enabled.api_v1:
73 cls.volumes_client = cls.manager.volumes_client
74 cls.snapshots_client = cls.manager.snapshots_client
75 else:
76 cls.volumes_client = cls.manager.volumes_v2_client
77 cls.snapshots_client = cls.manager.snapshots_v2_client
78
Andrea Frittoli247058f2014-07-16 16:09:22 +010079 # ## Methods to handle sync and async deletes
80
81 def setUp(self):
82 super(ScenarioTest, self).setUp()
83 self.cleanup_waits = []
84 # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
85 # because scenario tests in the same test class should not share
86 # resources. If resources were shared between test cases then it
87 # should be a single scenario test instead of multiples.
88
89 # NOTE(yfried): this list is cleaned at the end of test_methods and
90 # not at the end of the class
91 self.addCleanup(self._wait_for_cleanups)
92
Yair Fried1fc32a12014-08-04 09:11:30 +030093 def delete_wrapper(self, delete_thing, *args, **kwargs):
Andrea Frittoli247058f2014-07-16 16:09:22 +010094 """Ignores NotFound exceptions for delete operations.
95
Yair Fried1fc32a12014-08-04 09:11:30 +030096 @param delete_thing: delete method of a resource. method will be
97 executed as delete_thing(*args, **kwargs)
98
Andrea Frittoli247058f2014-07-16 16:09:22 +010099 """
100 try:
101 # Tempest clients return dicts, so there is no common delete
102 # method available. Using a callable instead
Yair Fried1fc32a12014-08-04 09:11:30 +0300103 delete_thing(*args, **kwargs)
Masayuki Igawabfa07602015-01-20 18:47:17 +0900104 except lib_exc.NotFound:
Andrea Frittoli247058f2014-07-16 16:09:22 +0100105 # If the resource is already missing, mission accomplished.
106 pass
107
108 def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
Ghanshyam2a180b82014-06-16 13:54:22 +0900109 cleanup_callable, cleanup_args=None,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000110 cleanup_kwargs=None, waiter_client=None):
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700111 """Adds wait for async resource deletion at the end of cleanups
Andrea Frittoli247058f2014-07-16 16:09:22 +0100112
113 @param waiter_callable: callable to wait for the resource to delete
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000114 with the following waiter_client if specified.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100115 @param thing_id: the id of the resource to be cleaned-up
116 @param thing_id_param: the name of the id param in the waiter
117 @param cleanup_callable: method to load pass to self.addCleanup with
118 the following *cleanup_args, **cleanup_kwargs.
119 usually a delete method.
120 """
Ghanshyam2a180b82014-06-16 13:54:22 +0900121 if cleanup_args is None:
122 cleanup_args = []
123 if cleanup_kwargs is None:
124 cleanup_kwargs = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100125 self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
126 wait_dict = {
127 'waiter_callable': waiter_callable,
128 thing_id_param: thing_id
129 }
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000130 if waiter_client:
131 wait_dict['client'] = waiter_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100132 self.cleanup_waits.append(wait_dict)
133
134 def _wait_for_cleanups(self):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000135 # To handle async delete actions, a list of waits is added
136 # which will be iterated over as the last step of clearing the
137 # cleanup queue. That way all the delete calls are made up front
138 # and the tests won't succeed unless the deletes are eventually
139 # successful. This is the same basic approach used in the api tests to
140 # limit cleanup execution time except here it is multi-resource,
141 # because of the nature of the scenario tests.
Andrea Frittoli247058f2014-07-16 16:09:22 +0100142 for wait in self.cleanup_waits:
143 waiter_callable = wait.pop('waiter_callable')
144 waiter_callable(**wait)
145
146 # ## Test functions library
147 #
148 # The create_[resource] functions only return body and discard the
149 # resp part which is not used in scenario tests
150
Yair Frieddb6c9e92014-08-06 08:53:13 +0300151 def create_keypair(self, client=None):
152 if not client:
153 client = self.keypairs_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100154 name = data_utils.rand_name(self.__class__.__name__)
155 # We don't need to create a keypair by pubkey in scenario
Ken'ichi Ohmichie364bce2015-07-17 10:27:59 +0000156 body = client.create_keypair(name=name)
Yair Frieddb6c9e92014-08-06 08:53:13 +0300157 self.addCleanup(client.delete_keypair, name)
ghanshyamdee01f22015-08-17 11:41:47 +0900158 return body['keypair']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100159
160 def create_server(self, name=None, image=None, flavor=None,
161 wait_on_boot=True, wait_on_delete=True,
Ghanshyam2a180b82014-06-16 13:54:22 +0900162 create_kwargs=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100163 """Creates VM instance.
164
165 @param image: image from which to create the instance
166 @param wait_on_boot: wait for status ACTIVE before continue
167 @param wait_on_delete: force synchronous delete on cleanup
168 @param create_kwargs: additional details for instance creation
169 @return: server dict
170 """
171 if name is None:
172 name = data_utils.rand_name(self.__class__.__name__)
173 if image is None:
174 image = CONF.compute.image_ref
175 if flavor is None:
176 flavor = CONF.compute.flavor_ref
Ghanshyam2a180b82014-06-16 13:54:22 +0900177 if create_kwargs is None:
178 create_kwargs = {}
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530179 network = self.get_tenant_network()
Matthew Treinish4bbc1992015-04-07 11:13:40 -0400180 create_kwargs = fixed_network.set_networks_kwarg(network,
181 create_kwargs)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100182
Andrea Frittoli247058f2014-07-16 16:09:22 +0100183 LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
184 name, image, flavor)
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +0000185 server = self.servers_client.create_server(name=name, imageRef=image,
186 flavorRef=flavor,
ghanshyam0f825252015-08-25 16:02:50 +0900187 **create_kwargs)['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100188 if wait_on_delete:
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000189 self.addCleanup(waiters.wait_for_server_termination,
190 self.servers_client,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100191 server['id'])
192 self.addCleanup_with_wait(
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000193 waiter_callable=waiters.wait_for_server_termination,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100194 thing_id=server['id'], thing_id_param='server_id',
195 cleanup_callable=self.delete_wrapper,
Ken'ichi Ohmichie91a0c62015-08-13 02:09:16 +0000196 cleanup_args=[self.servers_client.delete_server, server['id']],
197 waiter_client=self.servers_client)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100198 if wait_on_boot:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000199 waiters.wait_for_server_status(self.servers_client,
200 server_id=server['id'],
201 status='ACTIVE')
Andrea Frittoli247058f2014-07-16 16:09:22 +0100202 # The instance retrieved on creation is missing network
203 # details, necessitating retrieval after it becomes active to
204 # ensure correct details.
ghanshyam0f825252015-08-25 16:02:50 +0900205 server = self.servers_client.show_server(server['id'])['server']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100206 self.assertEqual(server['name'], name)
207 return server
208
Markus Zoeller3d2a21c2015-02-27 12:04:22 +0100209 def create_volume(self, size=None, name=None, snapshot_id=None,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100210 imageRef=None, volume_type=None, wait_on_delete=True):
211 if name is None:
212 name = data_utils.rand_name(self.__class__.__name__)
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000213 volume = self.volumes_client.create_volume(
Andrea Frittoli247058f2014-07-16 16:09:22 +0100214 size=size, display_name=name, snapshot_id=snapshot_id,
John Warren6177c9e2015-08-19 20:00:17 +0000215 imageRef=imageRef, volume_type=volume_type)['volume']
Matt Riedemanne85c2702014-09-10 11:50:13 -0700216
Andrea Frittoli247058f2014-07-16 16:09:22 +0100217 if wait_on_delete:
218 self.addCleanup(self.volumes_client.wait_for_resource_deletion,
219 volume['id'])
Matt Riedemanne85c2702014-09-10 11:50:13 -0700220 self.addCleanup(self.delete_wrapper,
221 self.volumes_client.delete_volume, volume['id'])
222 else:
223 self.addCleanup_with_wait(
224 waiter_callable=self.volumes_client.wait_for_resource_deletion,
225 thing_id=volume['id'], thing_id_param='id',
226 cleanup_callable=self.delete_wrapper,
227 cleanup_args=[self.volumes_client.delete_volume, volume['id']])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100228
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +0300229 # NOTE(e0ne): Cinder API v2 uses name instead of display_name
230 if 'display_name' in volume:
231 self.assertEqual(name, volume['display_name'])
232 else:
233 self.assertEqual(name, volume['name'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100234 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
235 # The volume retrieved on creation has a non-up-to-date status.
236 # Retrieval after it becomes active ensures correct details.
John Warren6177c9e2015-08-19 20:00:17 +0000237 volume = self.volumes_client.show_volume(volume['id'])['volume']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100238 return volume
239
Yair Fried1fc32a12014-08-04 09:11:30 +0300240 def _create_loginable_secgroup_rule(self, secgroup_id=None):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100241 _client = self.security_groups_client
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000242 _client_rules = self.security_group_rules_client
Andrea Frittoli247058f2014-07-16 16:09:22 +0100243 if secgroup_id is None:
ghanshyamb610b772015-08-24 17:29:38 +0900244 sgs = _client.list_security_groups()['security_groups']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100245 for sg in sgs:
246 if sg['name'] == 'default':
247 secgroup_id = sg['id']
248
249 # These rules are intended to permit inbound ssh and icmp
250 # traffic from all sources, so no group_id is provided.
251 # Setting a group_id would only permit traffic from ports
252 # belonging to the same security group.
253 rulesets = [
254 {
255 # ssh
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000256 'ip_protocol': 'tcp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100257 'from_port': 22,
258 'to_port': 22,
259 'cidr': '0.0.0.0/0',
260 },
261 {
262 # ping
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000263 'ip_protocol': 'icmp',
Andrea Frittoli247058f2014-07-16 16:09:22 +0100264 'from_port': -1,
265 'to_port': -1,
266 'cidr': '0.0.0.0/0',
267 }
268 ]
269 rules = list()
270 for ruleset in rulesets:
Ken'ichi Ohmichieb7eeec2015-07-21 01:00:06 +0000271 sg_rule = _client_rules.create_security_group_rule(
ghanshyam0a5e1232015-08-24 16:59:59 +0900272 parent_group_id=secgroup_id, **ruleset)['security_group_rule']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100273 self.addCleanup(self.delete_wrapper,
Ken'ichi Ohmichi685cd172015-07-13 01:29:57 +0000274 _client_rules.delete_security_group_rule,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100275 sg_rule['id'])
276 rules.append(sg_rule)
277 return rules
278
Yair Fried1fc32a12014-08-04 09:11:30 +0300279 def _create_security_group(self):
Andrea Frittoli247058f2014-07-16 16:09:22 +0100280 # Create security group
281 sg_name = data_utils.rand_name(self.__class__.__name__)
282 sg_desc = sg_name + " description"
David Kranz9964b4e2015-02-06 15:45:29 -0500283 secgroup = self.security_groups_client.create_security_group(
ghanshyamb610b772015-08-24 17:29:38 +0900284 name=sg_name, description=sg_desc)['security_group']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100285 self.assertEqual(secgroup['name'], sg_name)
286 self.assertEqual(secgroup['description'], sg_desc)
287 self.addCleanup(self.delete_wrapper,
288 self.security_groups_client.delete_security_group,
289 secgroup['id'])
290
291 # Add rules to the security group
Yair Fried1fc32a12014-08-04 09:11:30 +0300292 self._create_loginable_secgroup_rule(secgroup['id'])
Andrea Frittoli247058f2014-07-16 16:09:22 +0100293
294 return secgroup
295
JordanP3fe2dc32014-11-17 13:06:01 +0100296 def get_remote_client(self, server_or_ip, username=None, private_key=None,
297 log_console_of_servers=None):
298 """Get a SSH client to a remote server
299
300 @param server_or_ip a server object as returned by Tempest compute
301 client or an IP address to connect to
302 @param username name of the Linux account on the remote server
303 @param private_key the SSH private key to use
304 @param log_console_of_servers a list of server objects. Each server
305 in the list will have its console printed in the logs in case the
306 SSH connection failed to be established
307 @return a RemoteClient object
308 """
Andrea Frittoli247058f2014-07-16 16:09:22 +0100309 if isinstance(server_or_ip, six.string_types):
310 ip = server_or_ip
311 else:
Andrew Boik4a3daf12015-03-27 01:59:31 -0400312 addrs = server_or_ip['addresses'][CONF.compute.network_for_ssh]
313 try:
314 ip = (addr['addr'] for addr in addrs if
315 netaddr.valid_ipv4(addr['addr'])).next()
316 except StopIteration:
317 raise lib_exc.NotFound("No IPv4 addresses to use for SSH to "
318 "remote server.")
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700319
Andrea Frittoli247058f2014-07-16 16:09:22 +0100320 if username is None:
321 username = CONF.scenario.ssh_user
wantwatering896300c2015-03-27 15:17:42 +0800322 # Set this with 'keypair' or others to log in with keypair or
323 # username/password.
324 if CONF.compute.ssh_auth_method == 'keypair':
325 password = None
326 if private_key is None:
327 private_key = self.keypair['private_key']
328 else:
329 password = CONF.compute.image_ssh_password
330 private_key = None
Andrea Frittoli247058f2014-07-16 16:09:22 +0100331 linux_client = remote_client.RemoteClient(ip, username,
wantwatering896300c2015-03-27 15:17:42 +0800332 pkey=private_key,
333 password=password)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100334 try:
335 linux_client.validate_authentication()
Matt Riedemann5f0ac522015-05-21 09:16:24 -0700336 except Exception as e:
337 message = ('Initializing SSH connection to %(ip)s failed. '
338 'Error: %(error)s' % {'ip': ip, 'error': e})
339 caller = misc_utils.find_test_caller()
340 if caller:
341 message = '(%s) %s' % (caller, message)
342 LOG.exception(message)
Marc Kodererb06db502015-04-30 09:31:27 +0200343 # If we don't explicitly set for which servers we want to
JordanP3fe2dc32014-11-17 13:06:01 +0100344 # log the console output then all the servers will be logged.
345 # See the definition of _log_console_output()
346 self._log_console_output(log_console_of_servers)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100347 raise
348
349 return linux_client
350
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000351 def _image_create(self, name, fmt, path,
352 disk_format=None, properties=None):
Ghanshyam2a180b82014-06-16 13:54:22 +0900353 if properties is None:
354 properties = {}
Andrea Frittoli247058f2014-07-16 16:09:22 +0100355 name = data_utils.rand_name('%s-' % name)
356 image_file = open(path, 'rb')
357 self.addCleanup(image_file.close)
358 params = {
359 'name': name,
360 'container_format': fmt,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000361 'disk_format': disk_format or fmt,
Andrea Frittoli247058f2014-07-16 16:09:22 +0100362 'is_public': 'False',
363 }
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000364 params['properties'] = properties
John Warren66207252015-07-31 15:51:02 -0400365 image = self.image_client.create_image(**params)['image']
Andrea Frittoli247058f2014-07-16 16:09:22 +0100366 self.addCleanup(self.image_client.delete_image, image['id'])
367 self.assertEqual("queued", image['status'])
368 self.image_client.update_image(image['id'], data=image_file)
369 return image['id']
370
371 def glance_image_create(self):
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300372 img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
Andrea Frittoli247058f2014-07-16 16:09:22 +0100373 aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
374 ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
375 ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300376 img_container_format = CONF.scenario.img_container_format
377 img_disk_format = CONF.scenario.img_disk_format
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000378 img_properties = CONF.scenario.img_properties
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300379 LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000380 "properties: %s, ami: %s, ari: %s, aki: %s" %
Alessandro Pilottib7c1daa2014-08-16 14:24:13 +0300381 (img_path, img_container_format, img_disk_format,
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000382 img_properties, ami_img_path, ari_img_path, aki_img_path))
Andrea Frittoli247058f2014-07-16 16:09:22 +0100383 try:
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100384 image = self._image_create('scenario-img',
385 img_container_format,
386 img_path,
387 disk_format=img_disk_format,
388 properties=img_properties)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100389 except IOError:
390 LOG.debug("A qcow2 image was not found. Try to get a uec image.")
391 kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
392 ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
Evgeny Antyshev7ba0d5f2015-04-28 13:18:07 +0000393 properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk}
Jordan Pittier1e443ec2015-11-20 16:15:58 +0100394 image = self._image_create('scenario-ami', 'ami',
395 path=ami_img_path,
396 properties=properties)
397 LOG.debug("image:%s" % image)
398
399 return image
Andrea Frittoli247058f2014-07-16 16:09:22 +0100400
401 def _log_console_output(self, servers=None):
Matthew Treinish42a3f3a2014-09-04 15:04:53 -0400402 if not CONF.compute_feature_enabled.console_output:
403 LOG.debug('Console output not supported, cannot log')
404 return
Andrea Frittoli247058f2014-07-16 16:09:22 +0100405 if not servers:
David Kranzae99b9a2015-02-16 13:37:01 -0500406 servers = self.servers_client.list_servers()
Andrea Frittoli247058f2014-07-16 16:09:22 +0100407 servers = servers['servers']
408 for server in servers:
Brant Knudson566c5712014-09-24 20:04:50 -0500409 console_output = self.servers_client.get_console_output(
ghanshyam0f825252015-08-25 16:02:50 +0900410 server['id'], length=None)['output']
David Kranzae99b9a2015-02-16 13:37:01 -0500411 LOG.debug('Console output for %s\nbody=\n%s',
412 server['id'], console_output)
Andrea Frittoli247058f2014-07-16 16:09:22 +0100413
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000414 def _log_net_info(self, exc):
415 # network debug is called as part of ssh init
Andrey Pavlov64723762015-04-29 06:24:58 +0300416 if not isinstance(exc, lib_exc.SSHTimeout):
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000417 LOG.debug('Network information on a devstack host')
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000418
nithya-ganesan882595e2014-07-29 18:51:07 +0000419 def create_server_snapshot(self, server, name=None):
420 # Glance client
421 _image_client = self.image_client
422 # Compute client
423 _images_client = self.images_client
424 if name is None:
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +0000425 name = data_utils.rand_name('scenario-snapshot')
nithya-ganesan882595e2014-07-29 18:51:07 +0000426 LOG.debug("Creating a snapshot image for server: %s", server['name'])
Ken'ichi Ohmichi28f18672015-07-17 10:00:38 +0000427 image = _images_client.create_image(server['id'], name=name)
David Kranza5299eb2015-01-15 17:24:05 -0500428 image_id = image.response['location'].split('images/')[1]
nithya-ganesan882595e2014-07-29 18:51:07 +0000429 _image_client.wait_for_image_status(image_id, 'active')
430 self.addCleanup_with_wait(
431 waiter_callable=_image_client.wait_for_resource_deletion,
432 thing_id=image_id, thing_id_param='id',
433 cleanup_callable=self.delete_wrapper,
434 cleanup_args=[_image_client.delete_image, image_id])
David Kranz34f18782015-01-06 13:43:55 -0500435 snapshot_image = _image_client.get_image_meta(image_id)
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300436
437 bdm = snapshot_image.get('properties', {}).get('block_device_mapping')
438 if bdm:
439 bdm = json.loads(bdm)
440 if bdm and 'snapshot_id' in bdm[0]:
441 snapshot_id = bdm[0]['snapshot_id']
442 self.addCleanup(
443 self.snapshots_client.wait_for_resource_deletion,
444 snapshot_id)
445 self.addCleanup(
446 self.delete_wrapper, self.snapshots_client.delete_snapshot,
447 snapshot_id)
Andrey Pavlovd35957b2015-08-27 20:12:15 +0300448 self.snapshots_client.wait_for_snapshot_status(snapshot_id,
449 'available')
Andrey Pavlovc8bd4b12015-08-17 10:20:17 +0300450
nithya-ganesan882595e2014-07-29 18:51:07 +0000451 image_name = snapshot_image['name']
452 self.assertEqual(name, image_name)
453 LOG.debug("Created snapshot image %s for server %s",
454 image_name, server['name'])
455 return snapshot_image
456
Jordan Pittier7cf64762015-10-14 15:01:12 +0200457 def nova_volume_attach(self, server, volume_to_attach):
Joseph Lanoux6809bab2014-12-18 14:57:18 +0000458 volume = self.servers_client.attach_volume(
Jordan Pittier7cf64762015-10-14 15:01:12 +0200459 server['id'], volumeId=volume_to_attach['id'], device='/dev/%s'
ghanshyam0f825252015-08-25 16:02:50 +0900460 % CONF.compute.volume_device_name)['volumeAttachment']
Jordan Pittier7cf64762015-10-14 15:01:12 +0200461 self.assertEqual(volume_to_attach['id'], volume['id'])
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900462 self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900463
Jordan Pittier7cf64762015-10-14 15:01:12 +0200464 # Return the updated volume after the attachment
465 return self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900466
Jordan Pittier7cf64762015-10-14 15:01:12 +0200467 def nova_volume_detach(self, server, volume):
468 self.servers_client.detach_volume(server['id'], volume['id'])
469 self.volumes_client.wait_for_volume_status(volume['id'], 'available')
470
471 volume = self.volumes_client.show_volume(volume['id'])['volume']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +0900472 self.assertEqual('available', volume['status'])
473
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700474 def rebuild_server(self, server_id, image=None,
475 preserve_ephemeral=False, wait=True,
476 rebuild_kwargs=None):
477 if image is None:
478 image = CONF.compute.image_ref
479
480 rebuild_kwargs = rebuild_kwargs or {}
481
482 LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
483 server_id, image, preserve_ephemeral)
Ken'ichi Ohmichi5271b0f2015-08-10 07:53:27 +0000484 self.servers_client.rebuild_server(
485 server_id=server_id, image_ref=image,
486 preserve_ephemeral=preserve_ephemeral,
487 **rebuild_kwargs)
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700488 if wait:
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +0000489 waiters.wait_for_server_status(self.servers_client,
490 server_id, 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -0700491
Steven Hardyda2a8352014-10-02 12:52:20 +0100492 def ping_ip_address(self, ip_address, should_succeed=True,
493 ping_timeout=None):
494 timeout = ping_timeout or CONF.compute.ping_timeout
Aaron Rosena7df13b2014-09-23 09:45:45 -0700495 cmd = ['ping', '-c1', '-w1', ip_address]
496
497 def ping():
498 proc = subprocess.Popen(cmd,
499 stdout=subprocess.PIPE,
500 stderr=subprocess.PIPE)
501 proc.communicate()
Shuquan Huang753629e2015-07-20 08:52:29 +0000502
Aaron Rosena7df13b2014-09-23 09:45:45 -0700503 return (proc.returncode == 0) == should_succeed
504
Shuquan Huang753629e2015-07-20 08:52:29 +0000505 caller = misc_utils.find_test_caller()
506 LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the'
507 ' expected result is %(should_succeed)s' % {
508 'caller': caller, 'ip': ip_address, 'timeout': timeout,
509 'should_succeed':
510 'reachable' if should_succeed else 'unreachable'
511 })
512 result = tempest.test.call_until_true(ping, timeout, 1)
513 LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the '
514 'ping result is %(result)s' % {
515 'caller': caller, 'ip': ip_address, 'timeout': timeout,
516 'result': 'expected' if result else 'unexpected'
517 })
518 return result
Aaron Rosena7df13b2014-09-23 09:45:45 -0700519
Yair Friedae0e73d2014-11-24 11:56:26 +0200520 def check_vm_connectivity(self, ip_address,
521 username=None,
522 private_key=None,
523 should_connect=True):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000524 """Check server connectivity
525
Yair Friedae0e73d2014-11-24 11:56:26 +0200526 :param ip_address: server to test against
527 :param username: server's ssh username
528 :param private_key: server's ssh private key to be used
529 :param should_connect: True/False indicates positive/negative test
530 positive - attempt ping and ssh
531 negative - attempt ping and fail if succeed
532
533 :raises: AssertError if the result of the connectivity check does
534 not match the value of the should_connect param
535 """
536 if should_connect:
537 msg = "Timed out waiting for %s to become reachable" % ip_address
538 else:
539 msg = "ip address %s is reachable" % ip_address
540 self.assertTrue(self.ping_ip_address(ip_address,
541 should_succeed=should_connect),
542 msg=msg)
543 if should_connect:
544 # no need to check ssh for negative connectivity
545 self.get_remote_client(ip_address, username, private_key)
546
547 def check_public_network_connectivity(self, ip_address, username,
548 private_key, should_connect=True,
549 msg=None, servers=None):
550 # The target login is assumed to have been configured for
551 # key-based authentication by cloud-init.
552 LOG.debug('checking network connections to IP %s with user: %s' %
553 (ip_address, username))
554 try:
555 self.check_vm_connectivity(ip_address,
556 username,
557 private_key,
558 should_connect=should_connect)
Matthew Treinish53483132014-12-09 18:50:06 -0500559 except Exception:
Yair Friedae0e73d2014-11-24 11:56:26 +0200560 ex_msg = 'Public network connectivity check failed'
561 if msg:
562 ex_msg += ": " + msg
563 LOG.exception(ex_msg)
564 self._log_console_output(servers)
Yair Friedae0e73d2014-11-24 11:56:26 +0200565 raise
566
567 def create_floating_ip(self, thing, pool_name=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000568 """Create a floating IP and associates to a server on Nova"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200569
John Warrene74890a2015-11-11 15:18:01 -0500570 floating_ip = (self.compute_floating_ips_client.
571 create_floating_ip(pool_name)['floating_ip'])
Yair Friedae0e73d2014-11-24 11:56:26 +0200572 self.addCleanup(self.delete_wrapper,
John Warrene74890a2015-11-11 15:18:01 -0500573 self.compute_floating_ips_client.delete_floating_ip,
Yair Friedae0e73d2014-11-24 11:56:26 +0200574 floating_ip['id'])
John Warrene74890a2015-11-11 15:18:01 -0500575 self.compute_floating_ips_client.associate_floating_ip_to_server(
Yair Friedae0e73d2014-11-24 11:56:26 +0200576 floating_ip['ip'], thing['id'])
577 return floating_ip
578
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700579 def create_timestamp(self, server_or_ip, dev_name=None, mount_path='/mnt',
580 private_key=None):
581 ssh_client = self.get_remote_client(server_or_ip,
582 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300583 if dev_name is not None:
584 ssh_client.make_fs(dev_name)
Matt Riedemann076685a2015-09-30 14:38:16 -0700585 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300586 cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path
587 ssh_client.exec_command(cmd_timestamp)
588 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
589 % mount_path)
590 if dev_name is not None:
591 ssh_client.umount(mount_path)
592 return timestamp
593
Matt Riedemannfd5657d2015-09-30 14:47:07 -0700594 def get_timestamp(self, server_or_ip, dev_name=None, mount_path='/mnt',
595 private_key=None):
596 ssh_client = self.get_remote_client(server_or_ip,
597 private_key=private_key)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300598 if dev_name is not None:
Matt Riedemann076685a2015-09-30 14:38:16 -0700599 ssh_client.mount(dev_name, mount_path)
Alexander Gubanovabd154c2015-09-23 23:24:06 +0300600 timestamp = ssh_client.exec_command('sudo cat %s/timestamp'
601 % mount_path)
602 if dev_name is not None:
603 ssh_client.umount(mount_path)
604 return timestamp
605
Alexander Gubanovc8829f82015-11-12 10:35:13 +0200606 def get_server_or_ip(self, server):
607 if CONF.validation.connect_method == 'floating':
608 ip = self.create_floating_ip(server)['ip']
609 else:
610 ip = server
611 return ip
612
Andrea Frittoli2e733b52014-07-16 14:12:11 +0100613
Andrea Frittoli4971fc82014-09-25 10:22:20 +0100614class NetworkScenarioTest(ScenarioTest):
Yair Fried1fc32a12014-08-04 09:11:30 +0300615 """Base class for network scenario tests.
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000616
Yair Fried1fc32a12014-08-04 09:11:30 +0300617 This class provide helpers for network scenario tests, using the neutron
618 API. Helpers from ancestor which use the nova network API are overridden
619 with the neutron API.
620
621 This Class also enforces using Neutron instead of novanetwork.
622 Subclassed tests will be skipped if Neutron is not enabled
623
624 """
625
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000626 credentials = ['primary', 'admin']
627
Yair Fried1fc32a12014-08-04 09:11:30 +0300628 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +0000629 def skip_checks(cls):
630 super(NetworkScenarioTest, cls).skip_checks()
Andrea Frittoli2ddc2632014-09-25 11:03:00 +0100631 if not CONF.service_available.neutron:
632 raise cls.skipException('Neutron not available')
Yair Fried1fc32a12014-08-04 09:11:30 +0300633
634 @classmethod
Andrea Frittoliac20b5e2014-09-15 13:31:14 +0100635 def resource_setup(cls):
636 super(NetworkScenarioTest, cls).resource_setup()
Yair Fried1fc32a12014-08-04 09:11:30 +0300637 cls.tenant_id = cls.manager.identity_client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300638
John Warren94d8faf2015-09-15 12:22:24 -0400639 def _create_network(self, client=None, networks_client=None,
640 tenant_id=None, namestart='network-smoke-'):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300641 if not client:
642 client = self.network_client
John Warren94d8faf2015-09-15 12:22:24 -0400643 if not networks_client:
644 networks_client = self.networks_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300645 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000646 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300647 name = data_utils.rand_name(namestart)
John Warren94d8faf2015-09-15 12:22:24 -0400648 result = networks_client.create_network(name=name, tenant_id=tenant_id)
649 network = net_resources.DeletableNetwork(
650 networks_client=networks_client, **result['network'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300651 self.assertEqual(network.name, name)
652 self.addCleanup(self.delete_wrapper, network.delete)
653 return network
654
655 def _list_networks(self, *args, **kwargs):
656 """List networks using admin creds """
John Warren94d8faf2015-09-15 12:22:24 -0400657 networks_list = self.admin_manager.networks_client.list_networks(
ghanshyam2f7cc022015-06-26 18:18:11 +0900658 *args, **kwargs)
659 return networks_list['networks']
Yair Fried1fc32a12014-08-04 09:11:30 +0300660
661 def _list_subnets(self, *args, **kwargs):
662 """List subnets using admin creds """
John Warren3961acd2015-10-02 14:38:53 -0400663 subnets_list = self.admin_manager.subnets_client.list_subnets(
ghanshyam2f7cc022015-06-26 18:18:11 +0900664 *args, **kwargs)
665 return subnets_list['subnets']
Yair Fried1fc32a12014-08-04 09:11:30 +0300666
667 def _list_routers(self, *args, **kwargs):
668 """List routers using admin creds """
ghanshyam2f7cc022015-06-26 18:18:11 +0900669 routers_list = self.admin_manager.network_client.list_routers(
670 *args, **kwargs)
671 return routers_list['routers']
Yair Fried1fc32a12014-08-04 09:11:30 +0300672
673 def _list_ports(self, *args, **kwargs):
674 """List ports using admin creds """
John Warren49c0fe52015-10-22 12:35:54 -0400675 ports_list = self.admin_manager.ports_client.list_ports(
ghanshyam2f7cc022015-06-26 18:18:11 +0900676 *args, **kwargs)
677 return ports_list['ports']
Yair Fried1fc32a12014-08-04 09:11:30 +0300678
Yair Fried564d89d2015-08-06 17:02:12 +0300679 def _list_agents(self, *args, **kwargs):
680 """List agents using admin creds """
681 agents_list = self.admin_manager.network_client.list_agents(
682 *args, **kwargs)
683 return agents_list['agents']
684
John Warren3961acd2015-10-02 14:38:53 -0400685 def _create_subnet(self, network, client=None, subnets_client=None,
686 namestart='subnet-smoke', **kwargs):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000687 """Create a subnet for the given network
688
689 within the cidr block configured for tenant networks.
Yair Fried1fc32a12014-08-04 09:11:30 +0300690 """
Yair Frieddb6c9e92014-08-06 08:53:13 +0300691 if not client:
692 client = self.network_client
John Warren3961acd2015-10-02 14:38:53 -0400693 if not subnets_client:
694 subnets_client = self.subnets_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300695
696 def cidr_in_use(cidr, tenant_id):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000697 """Check cidr existence
698
Yair Fried1fc32a12014-08-04 09:11:30 +0300699 :return True if subnet with cidr already exist in tenant
700 False else
701 """
702 cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
703 return len(cidr_in_use) != 0
704
Kirill Shileev14113572014-11-21 16:58:02 +0300705 ip_version = kwargs.pop('ip_version', 4)
706
707 if ip_version == 6:
708 tenant_cidr = netaddr.IPNetwork(
709 CONF.network.tenant_network_v6_cidr)
710 num_bits = CONF.network.tenant_network_v6_mask_bits
711 else:
712 tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
713 num_bits = CONF.network.tenant_network_mask_bits
714
Yair Fried1fc32a12014-08-04 09:11:30 +0300715 result = None
Kirill Shileev14113572014-11-21 16:58:02 +0300716 str_cidr = None
Yair Fried1fc32a12014-08-04 09:11:30 +0300717 # Repeatedly attempt subnet creation with sequential cidr
718 # blocks until an unallocated block is found.
Kirill Shileev14113572014-11-21 16:58:02 +0300719 for subnet_cidr in tenant_cidr.subnet(num_bits):
Yair Fried1fc32a12014-08-04 09:11:30 +0300720 str_cidr = str(subnet_cidr)
721 if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
722 continue
723
724 subnet = dict(
725 name=data_utils.rand_name(namestart),
Yair Fried1fc32a12014-08-04 09:11:30 +0300726 network_id=network.id,
727 tenant_id=network.tenant_id,
728 cidr=str_cidr,
Kirill Shileev14113572014-11-21 16:58:02 +0300729 ip_version=ip_version,
Yair Fried1fc32a12014-08-04 09:11:30 +0300730 **kwargs
731 )
732 try:
John Warren3961acd2015-10-02 14:38:53 -0400733 result = subnets_client.create_subnet(**subnet)
Yair Fried1fc32a12014-08-04 09:11:30 +0300734 break
Masayuki Igawad9388762015-01-20 14:56:42 +0900735 except lib_exc.Conflict as e:
Yair Fried1fc32a12014-08-04 09:11:30 +0300736 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
737 if not is_overlapping_cidr:
738 raise
739 self.assertIsNotNone(result, 'Unable to allocate tenant network')
John Warren3961acd2015-10-02 14:38:53 -0400740 subnet = net_resources.DeletableSubnet(
741 network_client=client, subnets_client=subnets_client,
742 **result['subnet'])
Yair Fried1fc32a12014-08-04 09:11:30 +0300743 self.assertEqual(subnet.cidr, str_cidr)
744 self.addCleanup(self.delete_wrapper, subnet.delete)
745 return subnet
746
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200747 def _create_port(self, network_id, client=None, namestart='port-quotatest',
748 **kwargs):
Yair Frieddb6c9e92014-08-06 08:53:13 +0300749 if not client:
John Warren49c0fe52015-10-22 12:35:54 -0400750 client = self.ports_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300751 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -0500752 result = client.create_port(
Yair Fried1fc32a12014-08-04 09:11:30 +0300753 name=name,
Itzik Brown2ca01cd2014-12-08 12:58:20 +0200754 network_id=network_id,
755 **kwargs)
Yair Fried1fc32a12014-08-04 09:11:30 +0300756 self.assertIsNotNone(result, 'Unable to allocate port')
John Warren49c0fe52015-10-22 12:35:54 -0400757 port = net_resources.DeletablePort(ports_client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300758 **result['port'])
759 self.addCleanup(self.delete_wrapper, port.delete)
760 return port
761
Kirill Shileev14113572014-11-21 16:58:02 +0300762 def _get_server_port_id_and_ip4(self, server, ip_addr=None):
Ken'ichi Ohmichi30b769e2015-10-14 09:47:22 +0000763 ports = self._list_ports(device_id=server['id'], status='ACTIVE',
Yair Fried1fc32a12014-08-04 09:11:30 +0300764 fixed_ip=ip_addr)
Kirill Shileev14113572014-11-21 16:58:02 +0300765 # it might happen here that this port has more then one ip address
766 # as in case of dual stack- when this port is created on 2 subnets
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200767 port_map = [(p["id"], fxip["ip_address"])
768 for p in ports
769 for fxip in p["fixed_ips"]
770 if netaddr.valid_ipv4(fxip["ip_address"])]
771
John L. Villalovosb83286f2015-11-04 14:46:57 -0800772 self.assertNotEqual(0, len(port_map),
773 "No IPv4 addresses found in: %s" % ports)
Daniel Mellado9e3e1062015-08-06 18:07:05 +0200774 self.assertEqual(len(port_map), 1,
775 "Found multiple IPv4 addresses: %s. "
776 "Unable to determine which port to target."
777 % port_map)
778 return port_map[0]
Yair Fried1fc32a12014-08-04 09:11:30 +0300779
David Shrewsbury9bac3662014-08-07 15:07:01 -0400780 def _get_network_by_name(self, network_name):
781 net = self._list_networks(name=network_name)
Adam Gandelman878a5fd2015-03-30 14:33:36 -0700782 self.assertNotEqual(len(net), 0,
783 "Unable to get network by name: %s" % network_name)
Yair Fried8186f812014-09-28 09:39:39 +0300784 return net_resources.AttributeDict(net[0])
David Shrewsbury9bac3662014-08-07 15:07:01 -0400785
Yair Friedae0e73d2014-11-24 11:56:26 +0200786 def create_floating_ip(self, thing, external_network_id=None,
787 port_id=None, client=None):
Ken'ichi Ohmichia112a592015-11-17 08:49:37 +0000788 """Create a floating IP and associates to a resource/port on Neutron"""
Yair Friedae0e73d2014-11-24 11:56:26 +0200789 if not external_network_id:
790 external_network_id = CONF.network.public_network_id
Yair Frieddb6c9e92014-08-06 08:53:13 +0300791 if not client:
John Warrenfbf2a892015-11-17 12:36:14 -0500792 client = self.floating_ips_client
Yair Fried1fc32a12014-08-04 09:11:30 +0300793 if not port_id:
Kirill Shileev14113572014-11-21 16:58:02 +0300794 port_id, ip4 = self._get_server_port_id_and_ip4(thing)
795 else:
796 ip4 = None
David Kranz34e88122014-12-11 15:24:05 -0500797 result = client.create_floatingip(
Yair Fried1fc32a12014-08-04 09:11:30 +0300798 floating_network_id=external_network_id,
799 port_id=port_id,
Kirill Shileev14113572014-11-21 16:58:02 +0300800 tenant_id=thing['tenant_id'],
801 fixed_ip_address=ip4
Yair Fried1fc32a12014-08-04 09:11:30 +0300802 )
803 floating_ip = net_resources.DeletableFloatingIp(
Yair Frieddb6c9e92014-08-06 08:53:13 +0300804 client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +0300805 **result['floatingip'])
806 self.addCleanup(self.delete_wrapper, floating_ip.delete)
807 return floating_ip
808
809 def _associate_floating_ip(self, floating_ip, server):
Kirill Shileev14113572014-11-21 16:58:02 +0300810 port_id, _ = self._get_server_port_id_and_ip4(server)
Yair Fried1fc32a12014-08-04 09:11:30 +0300811 floating_ip.update(port_id=port_id)
812 self.assertEqual(port_id, floating_ip.port_id)
813 return floating_ip
814
815 def _disassociate_floating_ip(self, floating_ip):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000816 """:param floating_ip: type DeletableFloatingIp"""
Yair Fried1fc32a12014-08-04 09:11:30 +0300817 floating_ip.update(port_id=None)
818 self.assertIsNone(floating_ip.port_id)
819 return floating_ip
820
Yair Fried45f92952014-06-26 05:19:19 +0300821 def check_floating_ip_status(self, floating_ip, status):
Carl Baldwina754e2d2014-10-23 22:47:41 +0000822 """Verifies floatingip reaches the given status
Yair Fried45f92952014-06-26 05:19:19 +0300823
824 :param floating_ip: net_resources.DeletableFloatingIp floating IP to
825 to check status
826 :param status: target status
827 :raises: AssertionError if status doesn't match
828 """
Carl Baldwina754e2d2014-10-23 22:47:41 +0000829 def refresh():
830 floating_ip.refresh()
831 return status == floating_ip.status
832
833 tempest.test.call_until_true(refresh,
834 CONF.network.build_timeout,
835 CONF.network.build_interval)
Yair Fried45f92952014-06-26 05:19:19 +0300836 self.assertEqual(status, floating_ip.status,
837 message="FloatingIP: {fp} is at status: {cst}. "
838 "failed to reach status: {st}"
839 .format(fp=floating_ip, cst=floating_ip.status,
840 st=status))
841 LOG.info("FloatingIP: {fp} is at status: {st}"
842 .format(fp=floating_ip, st=status))
843
Yair Fried1fc32a12014-08-04 09:11:30 +0300844 def _check_tenant_network_connectivity(self, server,
845 username,
846 private_key,
847 should_connect=True,
848 servers_for_debug=None):
849 if not CONF.network.tenant_networks_reachable:
850 msg = 'Tenant networks not configured to be reachable.'
851 LOG.info(msg)
852 return
853 # The target login is assumed to have been configured for
854 # key-based authentication by cloud-init.
855 try:
Matthew Treinish71426682015-04-23 11:19:38 -0400856 for net_name, ip_addresses in six.iteritems(server['addresses']):
Yair Fried1fc32a12014-08-04 09:11:30 +0300857 for ip_address in ip_addresses:
ghanshyam807211c2014-12-18 13:21:22 +0900858 self.check_vm_connectivity(ip_address['addr'],
Yair Friedae0e73d2014-11-24 11:56:26 +0200859 username,
860 private_key,
861 should_connect=should_connect)
Yair Fried1fc32a12014-08-04 09:11:30 +0300862 except Exception as e:
863 LOG.exception('Tenant network connectivity check failed')
864 self._log_console_output(servers_for_debug)
Ken'ichi Ohmichi6e201f52014-10-01 04:21:39 +0000865 self._log_net_info(e)
Yair Fried1fc32a12014-08-04 09:11:30 +0300866 raise
867
868 def _check_remote_connectivity(self, source, dest, should_succeed=True):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +0000869 """check ping server via source ssh connection
Yair Fried1fc32a12014-08-04 09:11:30 +0300870
871 :param source: RemoteClient: an ssh connection from which to ping
872 :param dest: and IP to ping against
873 :param should_succeed: boolean should ping succeed or not
874 :returns: boolean -- should_succeed == ping
875 :returns: ping is false if ping failed
876 """
877 def ping_remote():
878 try:
879 source.ping_host(dest)
Andrey Pavlov64723762015-04-29 06:24:58 +0300880 except lib_exc.SSHExecCommandFailed:
Yair Fried1fc32a12014-08-04 09:11:30 +0300881 LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
882 % (dest, source.ssh_client.host))
883 return not should_succeed
884 return should_succeed
885
886 return tempest.test.call_until_true(ping_remote,
887 CONF.compute.ping_timeout,
888 1)
889
Yair Frieddb6c9e92014-08-06 08:53:13 +0300890 def _create_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300891 namestart='secgroup-smoke'):
892 if client is None:
893 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300894 if tenant_id is None:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000895 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300896 secgroup = self._create_empty_security_group(namestart=namestart,
897 client=client,
898 tenant_id=tenant_id)
899
900 # Add rules to the security group
ghanshyam38890b52015-01-21 15:24:18 +0900901 rules = self._create_loginable_secgroup_rule(client=client,
902 secgroup=secgroup)
Yair Fried1fc32a12014-08-04 09:11:30 +0300903 for rule in rules:
904 self.assertEqual(tenant_id, rule.tenant_id)
905 self.assertEqual(secgroup.id, rule.security_group_id)
906 return secgroup
907
Yair Frieddb6c9e92014-08-06 08:53:13 +0300908 def _create_empty_security_group(self, client=None, tenant_id=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300909 namestart='secgroup-smoke'):
910 """Create a security group without rules.
911
912 Default rules will be created:
913 - IPv4 egress to any
914 - IPv6 egress to any
915
916 :param tenant_id: secgroup will be created in this tenant
917 :returns: DeletableSecurityGroup -- containing the secgroup created
918 """
919 if client is None:
920 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300921 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000922 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300923 sg_name = data_utils.rand_name(namestart)
924 sg_desc = sg_name + " description"
925 sg_dict = dict(name=sg_name,
926 description=sg_desc)
927 sg_dict['tenant_id'] = tenant_id
David Kranz34e88122014-12-11 15:24:05 -0500928 result = client.create_security_group(**sg_dict)
Yair Fried1fc32a12014-08-04 09:11:30 +0300929 secgroup = net_resources.DeletableSecurityGroup(
930 client=client,
931 **result['security_group']
932 )
933 self.assertEqual(secgroup.name, sg_name)
934 self.assertEqual(tenant_id, secgroup.tenant_id)
935 self.assertEqual(secgroup.description, sg_desc)
936 self.addCleanup(self.delete_wrapper, secgroup.delete)
937 return secgroup
938
Yair Frieddb6c9e92014-08-06 08:53:13 +0300939 def _default_security_group(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +0300940 """Get default secgroup for given tenant_id.
941
942 :returns: DeletableSecurityGroup -- default secgroup for given tenant
943 """
944 if client is None:
945 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300946 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000947 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300948 sgs = [
949 sg for sg in client.list_security_groups().values()[0]
950 if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
951 ]
952 msg = "No default security group for tenant %s." % (tenant_id)
953 self.assertTrue(len(sgs) > 0, msg)
Yair Fried1fc32a12014-08-04 09:11:30 +0300954 return net_resources.DeletableSecurityGroup(client=client,
955 **sgs[0])
956
Yair Frieddb6c9e92014-08-06 08:53:13 +0300957 def _create_security_group_rule(self, secgroup=None, client=None,
Yair Fried1fc32a12014-08-04 09:11:30 +0300958 tenant_id=None, **kwargs):
959 """Create a rule from a dictionary of rule parameters.
960
961 Create a rule in a secgroup. if secgroup not defined will search for
962 default secgroup in tenant_id.
963
964 :param secgroup: type DeletableSecurityGroup.
Yair Fried1fc32a12014-08-04 09:11:30 +0300965 :param tenant_id: if secgroup not passed -- the tenant in which to
966 search for default secgroup
967 :param kwargs: a dictionary containing rule parameters:
968 for example, to allow incoming ssh:
969 rule = {
970 direction: 'ingress'
971 protocol:'tcp',
972 port_range_min: 22,
973 port_range_max: 22
974 }
975 """
976 if client is None:
977 client = self.network_client
Yair Frieddb6c9e92014-08-06 08:53:13 +0300978 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +0000979 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +0300980 if secgroup is None:
Yair Frieddb6c9e92014-08-06 08:53:13 +0300981 secgroup = self._default_security_group(client=client,
982 tenant_id=tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +0300983
984 ruleset = dict(security_group_id=secgroup.id,
985 tenant_id=secgroup.tenant_id)
986 ruleset.update(kwargs)
987
David Kranz34e88122014-12-11 15:24:05 -0500988 sg_rule = client.create_security_group_rule(**ruleset)
Yair Fried1fc32a12014-08-04 09:11:30 +0300989 sg_rule = net_resources.DeletableSecurityGroupRule(
990 client=client,
991 **sg_rule['security_group_rule']
992 )
993 self.addCleanup(self.delete_wrapper, sg_rule.delete)
994 self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
995 self.assertEqual(secgroup.id, sg_rule.security_group_id)
996
997 return sg_rule
998
999 def _create_loginable_secgroup_rule(self, client=None, secgroup=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001000 """Create loginable security group rule
1001
1002 These rules are intended to permit inbound ssh and icmp
Yair Fried1fc32a12014-08-04 09:11:30 +03001003 traffic from all sources, so no group_id is provided.
1004 Setting a group_id would only permit traffic from ports
1005 belonging to the same security group.
1006 """
1007
1008 if client is None:
1009 client = self.network_client
1010 rules = []
1011 rulesets = [
1012 dict(
1013 # ssh
1014 protocol='tcp',
1015 port_range_min=22,
1016 port_range_max=22,
1017 ),
1018 dict(
1019 # ping
1020 protocol='icmp',
Andreas Scheuring887ca8e2015-02-03 17:56:12 +01001021 ),
1022 dict(
1023 # ipv6-icmp for ping6
1024 protocol='icmp',
1025 ethertype='IPv6',
Yair Fried1fc32a12014-08-04 09:11:30 +03001026 )
1027 ]
1028 for ruleset in rulesets:
1029 for r_direction in ['ingress', 'egress']:
1030 ruleset['direction'] = r_direction
1031 try:
1032 sg_rule = self._create_security_group_rule(
1033 client=client, secgroup=secgroup, **ruleset)
Masayuki Igawad9388762015-01-20 14:56:42 +09001034 except lib_exc.Conflict as ex:
Yair Fried1fc32a12014-08-04 09:11:30 +03001035 # if rule already exist - skip rule and continue
1036 msg = 'Security group rule already exists'
1037 if msg not in ex._error_string:
1038 raise ex
1039 else:
1040 self.assertEqual(r_direction, sg_rule.direction)
1041 rules.append(sg_rule)
1042
1043 return rules
1044
1045 def _ssh_to_server(self, server, private_key):
1046 ssh_login = CONF.compute.image_ssh_user
1047 return self.get_remote_client(server,
1048 username=ssh_login,
1049 private_key=private_key)
1050
Yair Frieddb6c9e92014-08-06 08:53:13 +03001051 def _get_router(self, client=None, tenant_id=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001052 """Retrieve a router for the given tenant id.
1053
1054 If a public router has been configured, it will be returned.
1055
1056 If a public router has not been configured, but a public
1057 network has, a tenant router will be created and returned that
1058 routes traffic to the public network.
1059 """
Yair Frieddb6c9e92014-08-06 08:53:13 +03001060 if not client:
1061 client = self.network_client
1062 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001063 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001064 router_id = CONF.network.public_router_id
1065 network_id = CONF.network.public_network_id
1066 if router_id:
David Kranzca4c7e72015-05-27 11:39:19 -04001067 body = client.show_router(router_id)
Sergey Shnaidman5e9c8fd2014-09-30 18:31:43 +04001068 return net_resources.AttributeDict(**body['router'])
Yair Fried1fc32a12014-08-04 09:11:30 +03001069 elif network_id:
Yair Frieddb6c9e92014-08-06 08:53:13 +03001070 router = self._create_router(client, tenant_id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001071 router.set_gateway(network_id)
1072 return router
1073 else:
1074 raise Exception("Neither of 'public_router_id' or "
1075 "'public_network_id' has been defined.")
1076
Yair Frieddb6c9e92014-08-06 08:53:13 +03001077 def _create_router(self, client=None, tenant_id=None,
1078 namestart='router-smoke'):
1079 if not client:
1080 client = self.network_client
1081 if not tenant_id:
Ken'ichi Ohmichi88f12c12014-12-24 01:02:58 +00001082 tenant_id = client.tenant_id
Yair Fried1fc32a12014-08-04 09:11:30 +03001083 name = data_utils.rand_name(namestart)
David Kranz34e88122014-12-11 15:24:05 -05001084 result = client.create_router(name=name,
1085 admin_state_up=True,
1086 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001087 router = net_resources.DeletableRouter(client=client,
Yair Fried1fc32a12014-08-04 09:11:30 +03001088 **result['router'])
1089 self.assertEqual(router.name, name)
1090 self.addCleanup(self.delete_wrapper, router.delete)
1091 return router
1092
Alok Maurya6384bbb2014-07-13 06:44:29 -07001093 def _update_router_admin_state(self, router, admin_state_up):
1094 router.update(admin_state_up=admin_state_up)
1095 self.assertEqual(admin_state_up, router.admin_state_up)
1096
John Warren94d8faf2015-09-15 12:22:24 -04001097 def create_networks(self, client=None, networks_client=None,
John Warren3961acd2015-10-02 14:38:53 -04001098 subnets_client=None, tenant_id=None,
1099 dns_nameservers=None):
Yair Fried1fc32a12014-08-04 09:11:30 +03001100 """Create a network with a subnet connected to a router.
1101
David Shrewsbury9bac3662014-08-07 15:07:01 -04001102 The baremetal driver is a special case since all nodes are
1103 on the same shared network.
1104
Yair Fried413bf2d2014-11-19 17:07:11 +02001105 :param client: network client to create resources with.
1106 :param tenant_id: id of tenant to create resources in.
1107 :param dns_nameservers: list of dns servers to send to subnet.
Yair Fried1fc32a12014-08-04 09:11:30 +03001108 :returns: network, subnet, router
1109 """
David Shrewsbury9bac3662014-08-07 15:07:01 -04001110 if CONF.baremetal.driver_enabled:
1111 # NOTE(Shrews): This exception is for environments where tenant
1112 # credential isolation is available, but network separation is
1113 # not (the current baremetal case). Likely can be removed when
1114 # test account mgmt is reworked:
1115 # https://blueprints.launchpad.net/tempest/+spec/test-accounts
Adam Gandelman878a5fd2015-03-30 14:33:36 -07001116 if not CONF.compute.fixed_network_name:
1117 m = 'fixed_network_name must be specified in config'
1118 raise exceptions.InvalidConfiguration(m)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001119 network = self._get_network_by_name(
1120 CONF.compute.fixed_network_name)
1121 router = None
1122 subnet = None
1123 else:
John Warren94d8faf2015-09-15 12:22:24 -04001124 network = self._create_network(
1125 client=client, networks_client=networks_client,
1126 tenant_id=tenant_id)
Yair Frieddb6c9e92014-08-06 08:53:13 +03001127 router = self._get_router(client=client, tenant_id=tenant_id)
Yair Fried413bf2d2014-11-19 17:07:11 +02001128
John Warren3961acd2015-10-02 14:38:53 -04001129 subnet_kwargs = dict(network=network, client=client,
1130 subnets_client=subnets_client)
Yair Fried413bf2d2014-11-19 17:07:11 +02001131 # use explicit check because empty list is a valid option
1132 if dns_nameservers is not None:
1133 subnet_kwargs['dns_nameservers'] = dns_nameservers
1134 subnet = self._create_subnet(**subnet_kwargs)
David Shrewsbury9bac3662014-08-07 15:07:01 -04001135 subnet.add_to_router(router.id)
Yair Fried1fc32a12014-08-04 09:11:30 +03001136 return network, subnet, router
1137
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001138 def create_server(self, name=None, image=None, flavor=None,
1139 wait_on_boot=True, wait_on_delete=True,
John Warren94d8faf2015-09-15 12:22:24 -04001140 network_client=None, networks_client=None,
John Warren49c0fe52015-10-22 12:35:54 -04001141 ports_client=None, create_kwargs=None):
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001142 if network_client is None:
1143 network_client = self.network_client
John Warren94d8faf2015-09-15 12:22:24 -04001144 if networks_client is None:
1145 networks_client = self.networks_client
John Warren49c0fe52015-10-22 12:35:54 -04001146 if ports_client is None:
1147 ports_client = self.ports_client
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001148
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001149 vnic_type = CONF.network.port_vnic_type
1150
1151 # If vnic_type is configured create port for
1152 # every network
1153 if vnic_type:
1154 ports = []
1155 networks = []
1156 create_port_body = {'binding:vnic_type': vnic_type,
1157 'namestart': 'port-smoke'}
1158 if create_kwargs:
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001159 # Convert security group names to security group ids
1160 # to pass to create_port
1161 if create_kwargs.get('security_groups'):
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001162 security_groups = network_client.list_security_groups(
1163 ).get('security_groups')
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001164 sec_dict = dict([(s['name'], s['id'])
1165 for s in security_groups])
1166
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001167 sec_groups_names = [s['name'] for s in create_kwargs.get(
1168 'security_groups')]
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001169 security_groups_ids = [sec_dict[s]
1170 for s in sec_groups_names]
1171
1172 if security_groups_ids:
1173 create_port_body[
1174 'security_groups'] = security_groups_ids
1175 networks = create_kwargs.get('networks')
Ken'ichi Ohmichif2d436e2015-09-03 01:13:16 +00001176
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001177 # If there are no networks passed to us we look up
1178 # for the tenant's private networks and create a port
1179 # if there is only one private network. The same behaviour
1180 # as we would expect when passing the call to the clients
1181 # with no networks
1182 if not networks:
John Warren94d8faf2015-09-15 12:22:24 -04001183 networks = networks_client.list_networks(filters={
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001184 'router:external': False})
1185 self.assertEqual(1, len(networks),
1186 "There is more than one"
1187 " network for the tenant")
1188 for net in networks:
1189 net_id = net['uuid']
1190 port = self._create_port(network_id=net_id,
John Warren49c0fe52015-10-22 12:35:54 -04001191 client=ports_client,
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001192 **create_port_body)
1193 ports.append({'port': port.id})
1194 if ports:
1195 create_kwargs['networks'] = ports
Shuquan Huangb5c8beb2015-08-05 14:14:01 +00001196 self.ports = ports
Itzik Brown2ca01cd2014-12-08 12:58:20 +02001197
1198 return super(NetworkScenarioTest, self).create_server(
1199 name=name, image=image, flavor=flavor,
1200 wait_on_boot=wait_on_boot, wait_on_delete=wait_on_delete,
1201 create_kwargs=create_kwargs)
1202
Yair Fried1fc32a12014-08-04 09:11:30 +03001203
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001204# power/provision states as of icehouse
1205class BaremetalPowerStates(object):
1206 """Possible power states of an Ironic node."""
1207 POWER_ON = 'power on'
1208 POWER_OFF = 'power off'
1209 REBOOT = 'rebooting'
1210 SUSPEND = 'suspended'
1211
1212
1213class BaremetalProvisionStates(object):
1214 """Possible provision states of an Ironic node."""
1215 NOSTATE = None
1216 INIT = 'initializing'
1217 ACTIVE = 'active'
1218 BUILDING = 'building'
1219 DEPLOYWAIT = 'wait call-back'
1220 DEPLOYING = 'deploying'
1221 DEPLOYFAIL = 'deploy failed'
1222 DEPLOYDONE = 'deploy complete'
1223 DELETING = 'deleting'
1224 DELETED = 'deleted'
1225 ERROR = 'error'
1226
1227
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001228class BaremetalScenarioTest(ScenarioTest):
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001229
1230 credentials = ['primary', 'admin']
1231
Adam Gandelman4a48a602014-03-20 18:23:18 -07001232 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001233 def skip_checks(cls):
1234 super(BaremetalScenarioTest, cls).skip_checks()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001235 if (not CONF.service_available.ironic or
1236 not CONF.baremetal.driver_enabled):
1237 msg = 'Ironic not available or Ironic compute driver not enabled'
1238 raise cls.skipException(msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001239
1240 @classmethod
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001241 def setup_clients(cls):
1242 super(BaremetalScenarioTest, cls).setup_clients()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001243
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001244 cls.baremetal_client = cls.admin_manager.baremetal_client
Adam Gandelman4a48a602014-03-20 18:23:18 -07001245
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001246 @classmethod
1247 def resource_setup(cls):
1248 super(BaremetalScenarioTest, cls).resource_setup()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001249 # allow any issues obtaining the node list to raise early
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001250 cls.baremetal_client.list_nodes()
Adam Gandelman4a48a602014-03-20 18:23:18 -07001251
1252 def _node_state_timeout(self, node_id, state_attr,
1253 target_states, timeout=10, interval=1):
1254 if not isinstance(target_states, list):
1255 target_states = [target_states]
1256
1257 def check_state():
1258 node = self.get_node(node_id=node_id)
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001259 if node.get(state_attr) in target_states:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001260 return True
1261 return False
1262
1263 if not tempest.test.call_until_true(
1264 check_state, timeout, interval):
1265 msg = ("Timed out waiting for node %s to reach %s state(s) %s" %
1266 (node_id, state_attr, target_states))
1267 raise exceptions.TimeoutException(msg)
1268
1269 def wait_provisioning_state(self, node_id, state, timeout):
1270 self._node_state_timeout(
1271 node_id=node_id, state_attr='provision_state',
1272 target_states=state, timeout=timeout)
1273
1274 def wait_power_state(self, node_id, state):
1275 self._node_state_timeout(
1276 node_id=node_id, state_attr='power_state',
1277 target_states=state, timeout=CONF.baremetal.power_timeout)
1278
1279 def wait_node(self, instance_id):
1280 """Waits for a node to be associated with instance_id."""
Zhi Kun Liu4a8d1ea2014-04-15 22:08:21 -05001281
Adam Gandelman4a48a602014-03-20 18:23:18 -07001282 def _get_node():
1283 node = None
1284 try:
1285 node = self.get_node(instance_id=instance_id)
Masayuki Igawabfa07602015-01-20 18:47:17 +09001286 except lib_exc.NotFound:
Adam Gandelman4a48a602014-03-20 18:23:18 -07001287 pass
1288 return node is not None
1289
1290 if not tempest.test.call_until_true(
1291 _get_node, CONF.baremetal.association_timeout, 1):
1292 msg = ('Timed out waiting to get Ironic node by instance id %s'
1293 % instance_id)
1294 raise exceptions.TimeoutException(msg)
1295
1296 def get_node(self, node_id=None, instance_id=None):
1297 if node_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001298 _, body = self.baremetal_client.show_node(node_id)
1299 return body
Adam Gandelman4a48a602014-03-20 18:23:18 -07001300 elif instance_id:
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001301 _, body = self.baremetal_client.show_node_by_instance_uuid(
1302 instance_id)
1303 if body['nodes']:
1304 return body['nodes'][0]
Adam Gandelman4a48a602014-03-20 18:23:18 -07001305
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001306 def get_ports(self, node_uuid):
Adam Gandelman4a48a602014-03-20 18:23:18 -07001307 ports = []
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001308 _, body = self.baremetal_client.list_node_ports(node_uuid)
1309 for port in body['ports']:
1310 _, p = self.baremetal_client.show_port(port['uuid'])
1311 ports.append(p)
Adam Gandelman4a48a602014-03-20 18:23:18 -07001312 return ports
1313
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001314 def add_keypair(self):
1315 self.keypair = self.create_keypair()
1316
1317 def verify_connectivity(self, ip=None):
1318 if ip:
1319 dest = self.get_remote_client(ip)
1320 else:
1321 dest = self.get_remote_client(self.instance)
1322 dest.validate_authentication()
1323
1324 def boot_instance(self):
1325 create_kwargs = {
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001326 'key_name': self.keypair['name']
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001327 }
1328 self.instance = self.create_server(
Matthew Treinishb7144eb2013-12-13 22:57:35 +00001329 wait_on_boot=False, create_kwargs=create_kwargs)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001330
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001331 self.wait_node(self.instance['id'])
1332 self.node = self.get_node(instance_id=self.instance['id'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001333
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001334 self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001335
1336 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001337 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001338 [BaremetalProvisionStates.DEPLOYWAIT,
1339 BaremetalProvisionStates.ACTIVE],
1340 timeout=15)
1341
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001342 self.wait_provisioning_state(self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001343 BaremetalProvisionStates.ACTIVE,
1344 timeout=CONF.baremetal.active_timeout)
1345
Ken'ichi Ohmichi0eb153c2015-07-13 02:18:25 +00001346 waiters.wait_for_server_status(self.servers_client,
1347 self.instance['id'], 'ACTIVE')
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001348 self.node = self.get_node(instance_id=self.instance['id'])
ghanshyam0f825252015-08-25 16:02:50 +09001349 self.instance = (self.servers_client.show_server(self.instance['id'])
1350 ['server'])
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001351
1352 def terminate_instance(self):
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001353 self.servers_client.delete_server(self.instance['id'])
1354 self.wait_power_state(self.node['uuid'],
1355 BaremetalPowerStates.POWER_OFF)
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001356 self.wait_provisioning_state(
Adam Gandelmanc78c7572014-08-28 18:38:55 -07001357 self.node['uuid'],
David Shrewsbury06f7f8a2014-05-20 13:55:57 -04001358 BaremetalProvisionStates.NOSTATE,
1359 timeout=CONF.baremetal.unprovision_timeout)
1360
Adam Gandelman4a48a602014-03-20 18:23:18 -07001361
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001362class EncryptionScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001363 """Base class for encryption scenario tests"""
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001364
Andrea Frittolib21de6c2015-02-06 20:12:38 +00001365 credentials = ['primary', 'admin']
David Kranz4cc852b2015-03-09 14:57:11 -04001366
1367 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001368 def setup_clients(cls):
1369 super(EncryptionScenarioTest, cls).setup_clients()
Ivan Kolodyazhnybcfc32e2015-08-06 13:31:36 +03001370 if CONF.volume_feature_enabled.api_v1:
1371 cls.admin_volume_types_client = cls.os_adm.volume_types_client
1372 else:
1373 cls.admin_volume_types_client = cls.os_adm.volume_types_v2_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001374
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001375 def create_volume_type(self, client=None, name=None):
1376 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001377 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001378 if not name:
1379 name = 'generic'
Ken'ichi Ohmichi6ded8df2015-03-23 02:00:19 +00001380 randomized_name = data_utils.rand_name('scenario-type-' + name)
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001381 LOG.debug("Creating a volume type: %s", randomized_name)
Joseph Lanoux6809bab2014-12-18 14:57:18 +00001382 body = client.create_volume_type(
John Warrend053ded2015-08-13 15:22:48 +00001383 randomized_name)['volume_type']
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001384 self.assertIn('id', body)
1385 self.addCleanup(client.delete_volume_type, body['id'])
1386 return body
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001387
1388 def create_encryption_type(self, client=None, type_id=None, provider=None,
1389 key_size=None, cipher=None,
1390 control_location=None):
1391 if not client:
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001392 client = self.admin_volume_types_client
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001393 if not type_id:
1394 volume_type = self.create_volume_type()
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001395 type_id = volume_type['id']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001396 LOG.debug("Creating an encryption type for volume type: %s", type_id)
Masayuki Igawa1f0ad632014-08-05 13:36:56 +09001397 client.create_encryption_type(
1398 type_id, provider=provider, key_size=key_size, cipher=cipher,
John Warrend053ded2015-08-13 15:22:48 +00001399 control_location=control_location)['encryption']
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001400
Kaitlin Farr366a51f2014-04-21 12:43:54 -04001401
Masayuki Igawa0870db52015-09-18 21:08:36 +09001402class ObjectStorageScenarioTest(ScenarioTest):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001403 """Provide harness to do Object Storage scenario tests.
Chris Dent0d494112014-08-26 13:48:30 +01001404
1405 Subclasses implement the tests that use the methods provided by this
1406 class.
1407 """
1408
1409 @classmethod
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001410 def skip_checks(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001411 super(ObjectStorageScenarioTest, cls).skip_checks()
Chris Dent0d494112014-08-26 13:48:30 +01001412 if not CONF.service_available.swift:
1413 skip_msg = ("%s skipped as swift is not available" %
1414 cls.__name__)
1415 raise cls.skipException(skip_msg)
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001416
1417 @classmethod
1418 def setup_credentials(cls):
Masayuki Igawa60ea6c52014-10-15 17:32:14 +09001419 cls.set_network_resources()
Masayuki Igawa0870db52015-09-18 21:08:36 +09001420 super(ObjectStorageScenarioTest, cls).setup_credentials()
Matthew Treinish4a596932015-03-06 20:37:01 -05001421 operator_role = CONF.object_storage.operator_role
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +01001422 cls.os_operator = cls.get_client_manager(roles=[operator_role])
Emily Hugenbruch5e2d2a22015-02-25 21:35:45 +00001423
1424 @classmethod
1425 def setup_clients(cls):
Masayuki Igawa0870db52015-09-18 21:08:36 +09001426 super(ObjectStorageScenarioTest, cls).setup_clients()
Chris Dent0d494112014-08-26 13:48:30 +01001427 # Clients for Swift
Matthew Treinish8f268292015-02-24 20:01:36 -05001428 cls.account_client = cls.os_operator.account_client
1429 cls.container_client = cls.os_operator.container_client
1430 cls.object_client = cls.os_operator.object_client
Chris Dent0d494112014-08-26 13:48:30 +01001431
Chris Dentde456a12014-09-10 12:41:15 +01001432 def get_swift_stat(self):
Chris Dent0d494112014-08-26 13:48:30 +01001433 """get swift status for our user account."""
1434 self.account_client.list_account_containers()
1435 LOG.debug('Swift status information obtained successfully')
1436
Chris Dentde456a12014-09-10 12:41:15 +01001437 def create_container(self, container_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001438 name = container_name or data_utils.rand_name(
1439 'swift-scenario-container')
1440 self.container_client.create_container(name)
1441 # look for the container to assure it is created
Chris Dentde456a12014-09-10 12:41:15 +01001442 self.list_and_check_container_objects(name)
Chris Dent0d494112014-08-26 13:48:30 +01001443 LOG.debug('Container %s created' % (name))
Chris Dent1d4313a2014-10-28 12:16:48 +00001444 self.addCleanup(self.delete_wrapper,
1445 self.container_client.delete_container,
1446 name)
Chris Dent0d494112014-08-26 13:48:30 +01001447 return name
1448
Chris Dentde456a12014-09-10 12:41:15 +01001449 def delete_container(self, container_name):
Chris Dent0d494112014-08-26 13:48:30 +01001450 self.container_client.delete_container(container_name)
1451 LOG.debug('Container %s deleted' % (container_name))
1452
Chris Dentde456a12014-09-10 12:41:15 +01001453 def upload_object_to_container(self, container_name, obj_name=None):
Chris Dent0d494112014-08-26 13:48:30 +01001454 obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
1455 obj_data = data_utils.arbitrary_string()
1456 self.object_client.create_object(container_name, obj_name, obj_data)
Chris Dent1d4313a2014-10-28 12:16:48 +00001457 self.addCleanup(self.delete_wrapper,
1458 self.object_client.delete_object,
1459 container_name,
1460 obj_name)
Chris Dent0d494112014-08-26 13:48:30 +01001461 return obj_name, obj_data
1462
Chris Dentde456a12014-09-10 12:41:15 +01001463 def delete_object(self, container_name, filename):
Chris Dent0d494112014-08-26 13:48:30 +01001464 self.object_client.delete_object(container_name, filename)
Chris Dentde456a12014-09-10 12:41:15 +01001465 self.list_and_check_container_objects(container_name,
1466 not_present_obj=[filename])
Chris Dent0d494112014-08-26 13:48:30 +01001467
Chris Dentde456a12014-09-10 12:41:15 +01001468 def list_and_check_container_objects(self, container_name,
1469 present_obj=None,
1470 not_present_obj=None):
Ken'ichi Ohmichic4e4f1c2015-11-17 08:16:12 +00001471 # List objects for a given container and assert which are present and
1472 # which are not.
Ghanshyam2a180b82014-06-16 13:54:22 +09001473 if present_obj is None:
1474 present_obj = []
1475 if not_present_obj is None:
1476 not_present_obj = []
Chris Dent0d494112014-08-26 13:48:30 +01001477 _, object_list = self.container_client.list_container_contents(
1478 container_name)
1479 if present_obj:
1480 for obj in present_obj:
1481 self.assertIn(obj, object_list)
1482 if not_present_obj:
1483 for obj in not_present_obj:
1484 self.assertNotIn(obj, object_list)
1485
Chris Dentde456a12014-09-10 12:41:15 +01001486 def change_container_acl(self, container_name, acl):
Chris Dent0d494112014-08-26 13:48:30 +01001487 metadata_param = {'metadata_prefix': 'x-container-',
1488 'metadata': {'read': acl}}
1489 self.container_client.update_container_metadata(container_name,
1490 **metadata_param)
1491 resp, _ = self.container_client.list_container_metadata(container_name)
1492 self.assertEqual(resp['x-container-read'], acl)
1493
Chris Dentde456a12014-09-10 12:41:15 +01001494 def download_and_verify(self, container_name, obj_name, expected_data):
Chris Dent0d494112014-08-26 13:48:30 +01001495 _, obj = self.object_client.get_object(container_name, obj_name)
1496 self.assertEqual(obj, expected_data)